U
    M8c6Z                     @   st  d 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mZmZ dd	lmZ dd
lmZmZmZmZmZmZ eeZedZedZedZ dZ!e Z"e Z#G dd dZ$e$Z%G dd d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Z+G dd deZ,G dd  d Z-G d!d" d"Z.G d#d$ d$Z/dS )%a|  
NOTE: All classes and functions in this module are considered private and are
subject to abrupt breaking changes. Please do not use them directly.

To view the raw JSON that the objects in this module represent, please
go to any `endpoint-rule-set.json` file in /botocore/data/<service>/<api version>/
or you can look at the test files in /tests/unit/data/endpoints/valid-rules/
    N)Enum)	lru_cache)	Formatter)
NamedTuple)
xform_name)IPV4_REquoteurlparse)EndpointResolutionError)	ArnParserInvalidArnExceptionis_valid_ipv4_endpoint_urlis_valid_ipv6_endpoint_urlnormalize_url_pathpercent_encodez\{[a-zA-Z#]+\}z(\w+)\[(\d+)\]z^(?!-)[a-zA-Z\d-]{1,63}(?<!-)$d   c                   @   s   e Zd ZdZdd Zdd Zdd Zdd	 Zd
d Zdd Z	dd Z
dd Zdd Zdd Zdd Zdd Zdd Zdd Zdd Zd d! Zd"d# Zd$d% Zd&d' Zd(d) Zd*d+ Zd,d- Zd.d/ Zd0S )1RuleSetStandardLibraryz5Rule actions to be performed by the EndpointProvider.c                 C   s
   || _ d S N)partitions_data)selfr    r   >/tmp/pip-unpacked-wheel-ozje0y8b/botocore/endpoint_provider.py__init__:   s    zRuleSetStandardLibrary.__init__c                 C   s   t |tod|kS )zgDetermine if an object is a function object.

        :type argument: Any
        :rtype: bool
        fn
isinstancedictr   argumentr   r   r   is_func=   s    zRuleSetStandardLibrary.is_funcc                 C   s   t |tod|kS )zhDetermine if an object is a reference object.

        :type argument: Any
        :rtype: bool
        refr   r   r   r   r   is_refE   s    zRuleSetStandardLibrary.is_refc                 C   s   t |tot|dk	S )zlDetermine if an object contains a template string.

        :type argument: Any
        :rtpe: bool
        N)r   strTEMPLATE_STRING_REsearchr   r   r   r   is_templateM   s    
z"RuleSetStandardLibrary.is_templatec           
      C   sb   d}t |D ]N\}}}}|dk	rT|}|d}|D ]}	||	 }q4|| | 7 }q||7 }q|S )zResolve and inject values into a template string.

        :type value: str
        :type scope_vars: dict
        :rtype: str
         N#)STRING_FORMATTERparsesplit)
r   value
scope_varsresultliteral	reference_Ztemplate_valueZtemplate_paramsparamr   r   r   resolve_template_stringX   s    


z.RuleSetStandardLibrary.resolve_template_stringc                 C   sH   |  |r| ||S | |r.||d S | |rD| ||S |S )z{Return evaluated value based on type.

        :type value: Any
        :type scope_vars: dict
        :rtype: Any
        r    )r   call_functionr!   getr%   r2   )r   r+   r,   r   r   r   resolve_valuek   s    


z$RuleSetStandardLibrary.resolve_valuec                 C   s(   t | }|dkrd| }|ddS )zPNormalize function names.

        :type value: str
        :rtype: str
        notr0   .)r   replace)r   r+   Znormalized_namer   r   r   convert_func_name{   s    

z(RuleSetStandardLibrary.convert_func_namec                    sn    fdd|d D } |d }t|}|| }d|krj|d }| krbtd| dd| |< |S )	zCall the function with the resolved arguments and assign to `scope_vars`
        when applicable.

        :type func_signature: dict
        :type scope_vars: dict
        :rtype: Any
        c                    s   g | ]} | qS r   r5   ).0argr,   r   r   r   
<listcomp>   s   z8RuleSetStandardLibrary.call_function.<locals>.<listcomp>argvr   assignzAssignment z= already exists in scoped variables and cannot be overwrittenmsg)r9   getattrr
   )r   func_signaturer,   	func_args	func_namefuncr-   r@   r   r=   r   r3      s    

z$RuleSetStandardLibrary.call_functionc                 C   s   |dk	S )zYEvaluates whether a value is set.

        :type value: Any
        :rytpe: bool
        Nr   r   r+   r   r   r   is_set   s    zRuleSetStandardLibrary.is_setc                 C   sr   | dD ]b}t|}|dk	rd| \}}t|}||}|dksR|t|krX dS ||   S || }q
|S )ap  Find an attribute within a value given a path string. The path can contain
        the name of the attribute and an index in brackets. A period separating attribute
        names indicates the one to the right is nested. The index will always occur at
        the end of the path.

        :type value: dict or list
        :type path: str
        :rtype: Any
        r7   N)r*   GET_ATTR_REr$   groupsintr4   len)r   r+   pathpartmatchnameindexr   r   r   get_attr   s    



zRuleSetStandardLibrary.get_attrc                 C   s   |d }|d |d< |S )NoutputsidrQ   r   )r   	partitionoutputr   r   r   format_partition_output   s    z.RuleSetStandardLibrary.format_partition_outputc                 C   s$   t |d |d k	}||d kp"|S )NZregionRegexZregions)rerP   )r   ZregionrV   Zmatches_regexr   r   r   is_partition_match   s    z)RuleSetStandardLibrary.is_partition_matchc                 C   sH   | j d }|dk	r6|D ]}| ||r| |  S q|d }| |S )zbMatch a region string to an AWS partition.

        :type value: str
        :rtype: dict
        
partitionsNr   )r   rZ   rX   )r   r+   r[   rV   aws_partitionr   r   r   r\      s    
z$RuleSetStandardLibrary.aws_partitionc                 C   s   |dks| dsdS zt|}W n tk
r:   Y dS X t|d |d |d fsZdS |d|d< |d}|dd	d	|d
< |S )zeParse and validate string for ARN components.

        :type value: str
        :rtype: dict
        Nzarn:rV   ZserviceresourceaccountZ	accountId:/Z
resourceId)
startswith
ARN_PARSERZ	parse_arnr   allpopr8   r*   )r   r+   Zarn_dictr]   r   r   r   aws_parse_arn   s    
z$RuleSetStandardLibrary.aws_parse_arnc                    sT   |dks|dkr"| ddkr"dS |dkrFt fdd|dD S t|dk	S )zEvaluates whether a value is a valid host label per
        RFC 1123. If allow_subdomains is True, split on `.` and validate
        each component separately.

        :type value: str
        :type allow_subdomains: bool
        :rtype: bool
        NFr7   r   Tc                 3   s   | ]}  |d V  qdS FN)is_valid_host_labelr;   labelr   r   r   	<genexpr>   s   z=RuleSetStandardLibrary.is_valid_host_label.<locals>.<genexpr>)countrc   r*   VALID_HOST_LABEL_RErP   r   r+   allow_subdomainsr   rj   r   rg      s    	z*RuleSetStandardLibrary.is_valid_host_labelc                 C   sB   t dd ||fD s:dt| dt| d}t|d||kS )z|Evaluates two string values for equality.

        :type value1: str
        :type value2: str
        :rtype: bool
        c                 s   s   | ]}t |tV  qd S r   )r   r"   r;   valr   r   r   rk     s     z7RuleSetStandardLibrary.string_equals.<locals>.<genexpr>z!Both values must be strings, not  and r7   rA   rc   typer
   r   Zvalue1Zvalue2rB   r   r   r   string_equals  s    
z$RuleSetStandardLibrary.string_equalsc                 C   s   |dkrdS t |S )zcPerform percent-encoding on an input string.

        :type value: str
        :rytpe: str
        N)r   rH   r   r   r   
uri_encode  s    z!RuleSetStandardLibrary.uri_encodec                 C   s   |dkrdS t |}z
|j W n tk
r4   Y dS X |j}|j}|dksVt|dkrZdS |j}tt|}|	ds| d}||j
||t|pt|dS )z[Parse a URL string into components.

        :type value: str
        :rtype: dict
        N)httpshttpr   r`   )scheme	authorityrN   ZnormalizedPathZisIp)r	   port
ValueErrorrz   queryrM   rN   r   r   endswithnetlocr   r   )r   r+   Zurl_componentsrz   r~   rN   Znormalized_pathr   r   r   	parse_url  s,    


z RuleSetStandardLibrary.parse_urlc                 C   sB   t dd ||fD s:dt| dt| d}t|d||kS )zEvaluates two boolean values for equality.

        :type value1: bool
        :type value2: bool
        :rtype: bool
        c                 s   s   | ]}t |tV  qd S r   )r   boolrp   r   r   r   rk   J  s     z8RuleSetStandardLibrary.boolean_equals.<locals>.<genexpr>z"Both arguments must be bools, not rr   r7   rA   rs   ru   r   r   r   boolean_equalsC  s    
z%RuleSetStandardLibrary.boolean_equalsc                 C   s,   z| d W dS  tk
r&   Y dS X dS )zmEvaluates if a string only contains ASCII characters.

        :type value: str
        :rtype: bool
        asciiTFN)encodeUnicodeEncodeErrorrH   r   r   r   is_asciiO  s
    
zRuleSetStandardLibrary.is_asciic                 C   s~   t |ts$dt| d}t|d||ksBt||k sB| |sFdS |dkrrt|| }t|| }||| S ||| S )a  Computes a substring given the start index and end index. If `reverse` is
        True, slice the string from the end instead.

        :type value: str
        :type start: int
        :type end: int
        :type reverse: bool
        :rtype: str
        zInput must be a string, not r7   rA   NT)r   r"   rt   r
   rM   r   )r   r+   startstopreverserB   Zr_startZr_stopr   r   r   	substring[  s    


z RuleSetStandardLibrary.substringc                 C   s   | S )zpA function implementation of the logical operator `not`.

        :type value: Any
        :rtype: bool
        r   rH   r   r   r   _notr  s    zRuleSetStandardLibrary._notc                    sd   |dks.t |dk s.| |ks.t|dk	r2dS |dkrVt fdd|dD S  j|ddS )	a  Evaluates whether a value is a valid bucket name for virtual host
        style bucket URLs. To pass, the value must meet the following criteria:
        1. is_valid_host_label(value) is True
        2. length between 3 and 63 characters (inclusive)
        3. does not contain uppercase characters
        4. is not formatted as an IP address

        If allow_subdomains is True, split on `.` and validate
        each component separately.

        :type value: str
        :type allow_subdomains: bool
        :rtype: bool
        N   FTc                 3   s   | ]}  |d V  qdS rf   )!aws_is_virtual_hostable_s3_bucketrh   rj   r   r   rk     s   zKRuleSetStandardLibrary.aws_is_virtual_hostable_s3_bucket.<locals>.<genexpr>r7   )ro   )rM   lowerr   rP   rc   r*   rg   rn   r   rj   r   r   z  s    

z8RuleSetStandardLibrary.aws_is_virtual_hostable_s3_bucketN)__name__
__module____qualname____doc__r   r   r!   r%   r2   r5   r9   r3   rI   rS   rX   rZ   r\   re   rg   rv   rw   r   r   r   r   r   r   r   r   r   r   r   7   s0   %r   c                   @   s*   e Zd ZdZd	ddZdd Zdd ZdS )
BaseRulez-Base interface for individual endpoint rules.Nc                 C   s   || _ || _d S r   )
conditionsdocumentation)r   r   r   r   r   r   r     s    zBaseRule.__init__c                 C   s
   t  d S r   )NotImplementedError)r   r,   rule_libr   r   r   evaluate  s    zBaseRule.evaluatec                 C   s2   | j D ]&}|||}|dks&|dkr dS qdS )zDetermine if all conditions in a rule are met.

        :type scope_vars: dict
        :type rule_lib: RuleSetStandardLibrary
        :rtype: bool
        FNT)r   r3   )r   r,   r   rD   r-   r   r   r   evaluate_conditions  s
    
zBaseRule.evaluate_conditions)N)r   r   r   r   r   r   r   r   r   r   r   r     s   
r   c                   @   s*   e Zd ZU dZeed< eed< eed< dS )RuleSetEndpointz.A resolved endpoint object returned by a rule.url
propertiesheadersN)r   r   r   r   r"   __annotations__r   r   r   r   r   r     s   
r   c                       s4   e Zd Z fddZdd Zdd Zdd Z  ZS )	EndpointRulec                    s   t  jf | || _d S r   )superr   endpoint)r   r   kwargs	__class__r   r   r     s    zEndpointRule.__init__c                 C   sT   |  ||rP|| jd |}| | jdi ||}| ||}t|||dS dS )zDetermine if conditions are met to provide a valid endpoint.

        :type scope_vars: dict
        :rtype: RuleSetEndpoint
        r   r   )r   r   r   N)r   r5   r   resolve_propertiesr4   resolve_headersr   )r   r,   r   r   r   r   r   r   r   r     s      zEndpointRule.evaluatec                    s^   t |tr  fdd|D S t |trD fdd| D S  |rZ |S |S )zTraverse `properties` attribute, resolving any template strings.

        :type properties: dict/list/str
        :type scope_vars: dict
        :type rule_lib: RuleSetStandardLibrary
        :rtype: dict
        c                    s   g | ]} | qS r   r   )r;   propr   r,   r   r   r   r>     s   z3EndpointRule.resolve_properties.<locals>.<listcomp>c                    s    i | ]\}}| | qS r   r   r;   keyr+   r   r   r   
<dictcomp>  s    z3EndpointRule.resolve_properties.<locals>.<dictcomp>)r   listr   itemsr%   r2   )r   r   r,   r   r   r   r   r     s    


zEndpointRule.resolve_propertiesc                    s@   i }| j di }| D ] \}} fdd|D ||< q|S )zIterate through headers attribute resolving all values.

        :type scope_vars: dict
        :type rule_lib: RuleSetStandardLibrary
        :rtype: dict
        r   c                    s   g | ]}  |qS r   r:   )r;   itemr   r,   r   r   r>     s    z0EndpointRule.resolve_headers.<locals>.<listcomp>)r   r4   r   )r   r,   r   Zresolved_headersr   headervaluesr   r   r   r     s    zEndpointRule.resolve_headers)r   r   r   r   r   r   r   __classcell__r   r   r   r   r     s   r   c                       s$   e Zd Z fddZdd Z  ZS )	ErrorRulec                    s   t  jf | || _d S r   )r   r   error)r   r   r   r   r   r   r     s    zErrorRule.__init__c                 C   s(   |  ||r$|| j|}t|ddS )zIf an error rule's conditions are met, raise an error rule.

        :type scope_vars: dict
        :type rule_lib: RuleSetStandardLibrary
        :rtype: EndpointResolutionError
        rA   N)r   r5   r   r
   )r   r,   r   r   r   r   r   r     s    
zErrorRule.evaluate)r   r   r   r   r   r   r   r   r   r   r      s   r   c                       s(   e Zd ZdZ fddZdd Z  ZS )TreeRulezA tree rule is non-terminal meaning it will never be returned to a provider.
    Additionally this means it has no attributes that need to be resolved.
    c                    s"   t  jf | dd |D | _d S )Nc                 S   s   g | ]}t jf |qS r   RuleCreatorcreater;   ruler   r   r   r>     s     z%TreeRule.__init__.<locals>.<listcomp>)r   r   rules)r   r   r   r   r   r   r     s    zTreeRule.__init__c                 C   s8   |  ||r4| jD ] }|| |}|r|  S qdS )zIf a tree rule's conditions are met, iterate its sub-rules
        and return first result found.

        :type scope_vars: dict
        :type rule_lib: RuleSetStandardLibrary
        :rtype: RuleSetEndpoint/EndpointResolutionError
        N)r   r   r   copy)r   r,   r   r   Zrule_resultr   r   r   r     s    

zTreeRule.evaluate)r   r   r   r   r   r   r   r   r   r   r   r     s   r   c                   @   s$   e Zd ZeZeZeZe	dd Z
dS )r   c                 K   sN   | d}zt| |}W n& tk
r>   td| ddY nX |f |S dS )z_Create a rule instance from metadata.

        :rtype: TreeRule/EndpointRule/ErrorRule
        rt   zUnknown rule type: z1. A rule must be of type tree, endpoint or error.rA   N)rd   rC   AttributeErrorr
   )clsr   Z	rule_typeZ
rule_classr   r   r   r   2  s    

zRuleCreator.createN)r   r   r   r   r   r   r   r   treeclassmethodr   r   r   r   r   r   ,  s
   r   c                   @   s   e Zd ZdZeZeZdS )ParameterTypez8Translation from `type` attribute to native Python type.N)r   r   r   r   r"   stringr   booleanr   r   r   r   r   D  s   r   c                   @   s*   e Zd ZdZd	ddZdd Zdd ZdS )
ParameterDefinitionz9The spec of an individual parameter defined in a RuleSet.Nc                 C   sf   || _ ztt| j| _W n& tk
rB   td| ddY nX || _|| _	|| _
|| _|| _d S )NzUnknown parameter type: z0. A parameter must be of type string or boolean.rA   )rQ   rC   r   r   r+   parameter_typer   r
   r   builtindefaultrequired
deprecated)r   rQ   r   r   builtInr   r   r   r   r   r   r   N  s    
 
zParameterDefinition.__init__c                 C   s   t || js(td| j d| j dd| jdk	r| j d}| jd}| jd}|rh|d	| 7 }|r||d
| d7 }t| dS )zwPerform base validation on parameter input.

        :type value: Any
        :raises: EndpointParametersError
        zValue (z) is the wrong type. Must be r7   rA   Nz has been deprecated.messagesince
z
Deprecated since )r   r   r
   rQ   r   r4   loggerinfo)r   r+   Zdepr_strrB   r   r   r   r   validate_inputh  s    

z"ParameterDefinition.validate_inputc                 C   s>   |dkr0| j dk	r| j S | jr:td| j n
| | |S )z>Process input against spec, applying default if value is None.Nz)Cannot find value for required parameter )r   r   r
   rQ   r   rH   r   r   r   process_input  s    


z!ParameterDefinition.process_input)NNNNN)r   r   r   r   r   r   r   r   r   r   r   r   K  s        
r   c                   @   s2   e Zd ZdZdddZdd Zdd Zd	d
 ZdS )RuleSetz:Collection of rules to derive a routable service endpoint.Nc                 C   s6   || _ | || _dd |D | _t|| _|| _d S )Nc                 S   s   g | ]}t jf |qS r   r   r   r   r   r   r>     s     z$RuleSet.__init__.<locals>.<listcomp>)version_ingest_parameter_spec
parametersr   r   r   r   )r   r   r   r   r[   r   r   r   r   r     s
    
zRuleSet.__init__c                 C   s   dd |  D S )Nc                 S   sH   i | ]@\}}|t ||d  |d|d|d|d|dqS )rt   r   r   r   r   r   )r   r4   )r;   rQ   specr   r   r   r     s   
 z2RuleSet._ingest_parameter_spec.<locals>.<dictcomp>)r   )r   r   r   r   r   r     s    
zRuleSet._ingest_parameter_specc                 C   s8   | j  D ](\}}|||}|dk	r
|||< q
dS )zYProcess each input parameter against its spec.

        :type input_params: dict
        N)r   r   r   r4   )r   Zinput_paramsrQ   r   r+   r   r   r   process_input_parameters  s
    
z RuleSet.process_input_parametersc                 C   s<   |  | | jD ]&}|| | j}|dk	r|  S qdS )zmEvaluate input parameters against rules returning first match.

        :type input_parameters: dict
        N)r   r   r   r   r   )r   input_parametersr   Z
evaluationr   r   r   r     s    


zRuleSet.evaluate)N)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eeddd ZdS )EndpointProviderz<Derives endpoints from a RuleSet for given input parameters.c                 C   s   t f |d|i| _d S )Nr[   )r   ruleset)r   Zruleset_dataZpartition_datar   r   r   r     s    zEndpointProvider.__init__)maxsizec                 K   sH   |  }| j|}|dkrDddd | D }td| d|S )zpMatch input parameters to a rule.

        :type input_parameters: dict
        :rtype: RuleSetEndpoint
        Nr   c                 S   s   g | ]\}}| d | qS )z: r   r   r   r   r   r>     s     z5EndpointProvider.resolve_endpoint.<locals>.<listcomp>z"No endpoint found for parameters:
rA   )r   r   r   joinr   r
   )r   r   Zparams_for_errorr   Zparam_stringr   r   r   resolve_endpoint  s    z!EndpointProvider.resolve_endpointN)r   r   r   r   r   r   
CACHE_SIZEr   r   r   r   r   r     s   r   )0r   loggingrY   enumr   	functoolsr   r   r   typingr   Zbotocorer   Zbotocore.compatr   r   r	   Zbotocore.exceptionsr
   Zbotocore.utilsr   r   r   r   r   r   	getLoggerr   r   compiler#   rJ   rm   r   rb   r(   r   ZRuleSetStandardLibaryr   r   r   r   r   r   r   r   r   r   r   r   r   r   <module>   sB   
 	


  gAD2