U
    Zf3H                     @   s$  d dl mZmZmZmZ d dlmZ d dlmZ d dl	Z	ddl
mZmZmZmZmZ dZerd dlZddl
mZmZmZmZmZmZmZmZ d d	lmZ e	jrejejd
f Z nejejdf 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'dS )    )absolute_importdivisionprint_functionunicode_literals)OrderedDict)StrictVersionN   )
doc_unwrapis_aliasis_composite_typeis_list_typeis_nullable_typeF)Alias
AnnotationAnnotationTypeDataTypeListNullableStructUserDefined)AstRouteDefApiNamespaces   ApiNamespacec                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )ApizL
    A full description of an API's namespaces, data types, and routes.
    c                 C   s   t || _t | _d | _d S N)r   versionr   
namespacesroute_schema)selfr    r   0/tmp/pip-unpacked-wheel-vqb3mfeu/stone/ir/api.py__init__.   s    
zApi.__init__c                 C   s"   || j krt|| j |< | j | S )z
        Only creates a namespace if it hasn't yet been defined.

        :param str name: Name of the namespace.

        :return ApiNamespace:
        )r   r   r   namer   r   r   ensure_namespace4   s    	
zApi.ensure_namespacec                 C   sJ   t  }t| j D ]}| j| ||< q|| _| j D ]}|  q8dS )zj
        Alphabetizes namespaces and routes to make spec parsing order mostly
        irrelevant.
        N)r   sortedr   keysvalues	normalize)r   Zordered_namespacesZnamespace_name	namespacer   r   r   r'   A   s    zApi.normalizec                 C   s   | j d kst|| _ d S r   )r   AssertionError)r   r   r   r   r   add_route_schemaP   s    zApi.add_route_schemaN)__name__
__module____qualname____doc__r    r#   r'   r*   r   r   r   r   r   *   s
   r   c                   @   s   e Zd ZdZdd ZdS )_ImportReasonz5
    Tracks the reason a namespace was imported.
    c                 C   s   d| _ d| _d| _d| _d S )NF)alias	data_type
annotationannotation_typer   r   r   r   r    [   s    z_ImportReason.__init__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d Zdd Zdd	 Zd
d Zdd Z	dd Z
d$ddZdd Zdd Zdd Zdd Zd%ddZdd Zdd  Zd!d" Zd#S )&r   zQ
    Represents a category of API endpoints and their associated data types.
    c                 C   sX   || _ d | _g | _i | _i | _g | _i | _g | _i | _g | _	i | _
g | _i | _i | _d S r   )r"   docroutesroute_by_nameroutes_by_name
data_typesdata_type_by_namealiasesalias_by_nameannotationsannotation_by_nameannotation_typesannotation_type_by_name_imported_namespacesr!   r   r   r   r    h   s    zApiNamespace.__init__c                 C   sH   t |tjstt|t|d }| jdkr6|| _n|  j|7  _dS )aU  Adds a docstring for this namespace.

        The input docstring is normalized to have no leading whitespace and
        no trailing whitespace except for a newline at the end.

        If a docstring already exists, the new normalized docstring is appended
        to the end of the existing one with two newlines separating them.
        
N)
isinstancesix	text_typer)   typer	   r6   )r   Z	docstringZnormalized_docstringr   r   r   add_docz   s
    

zApiNamespace.add_docc                 C   sT   | j | |jdkr"|| j|j< |j| jkr<t | j|j< || j|j j|j< d S )Nr   )r7   appendr   r8   r"   r9   ApiRoutesByVersion
at_version)r   router   r   r   	add_route   s    
zApiNamespace.add_routec                 C   s   | j | || j|j< d S r   )r:   rI   r;   r"   r   r1   r   r   r   add_data_type   s    zApiNamespace.add_data_typec                 C   s   | j | || j|j< d S r   )r<   rI   r=   r"   r   r0   r   r   r   	add_alias   s    zApiNamespace.add_aliasc                 C   s   | j | || j|j< d S r   )r>   rI   r?   r"   )r   r2   r   r   r   add_annotation   s    zApiNamespace.add_annotationc                 C   s   | j | || j|j< d S r   )r@   rI   rA   r"   )r   r3   r   r   r   add_annotation_type   s    z ApiNamespace.add_annotation_typeFc                 C   sP   | j |j kstd| j|t }|r.d|_|r8d|_|rBd|_|rLd|_dS )a  
        Keeps track of namespaces that this namespace imports.

        Args:
            namespace (Namespace): The imported namespace.
            imported_alias (bool): Set if this namespace references an alias
                in the imported namespace.
            imported_data_type (bool): Set if this namespace references a
                data type in the imported namespace.
            imported_annotation (bool): Set if this namespace references a
                annotation in the imported namespace.
            imported_annotation_type (bool): Set if this namespace references an
                annotation in the imported namespace, possibly indirectly (by
                referencing an annotation elsewhere that has this type).
        zNamespace cannot import itself.TN)	r"   r)   rB   
setdefaultr/   r0   r1   r2   r3   )r   r(   Zimported_aliasZimported_data_typeZimported_annotationZimported_annotation_typereasonr   r   r   add_imported_namespace   s    z#ApiNamespace.add_imported_namespacec                    s4   g t   fdd jD ]} | q"S )ad  
        Returns a list of all data types used in the namespace. Because the
        inheritance of data types can be modeled as a DAG, the list will be a
        linearization of the DAG. It's ideal to generate data types in this
        order so that composite types that reference other composite types are
        defined in the correct order.
        c                    sJ   | krd S | j krd S t| r2| jr2 | j |  |  d S r   )r(   r   Zparent_typerI   addr1   rO   Zlinearized_data_typesZseen_data_typesr   r   r   rO      s    


z8ApiNamespace.linearize_data_types.<locals>.add_data_type)setr:   rN   r   rY   r   linearize_data_types   s    	

z!ApiNamespace.linearize_data_typesc                    s4   g t   fdd jD ]} | q"S )z
        Returns a list of all aliases used in the namespace. The aliases are
        ordered to ensure that if they reference other aliases those aliases
        come earlier in the list.
        c                    sF   | krd S | j krd S t| jr. | j |  |  d S r   )r(   r
   r1   rI   rW   r0   rQ   Zlinearized_aliasesZseen_aliasesr   r   r   rQ      s    



z1ApiNamespace.linearize_aliases.<locals>.add_alias)rZ   r<   rP   r   r]   r   linearize_aliases   s    

zApiNamespace.linearize_aliasesc                 C   s0   t  }| jD ]}|| |O }qt|dd dS )a  
        Returns a list of all user-defined data types that are referenced as
        either an argument, result, or error of a route. If a List or Nullable
        data type is referenced, then the contained data type is returned
        assuming it's a user-defined type.
        c                 S   s   | j S r   r"   dtr   r   r   <lambda>      z6ApiNamespace.get_route_io_data_types.<locals>.<lambda>key)rZ   r7   !get_route_io_data_types_for_router$   )r   r:   rL   r   r   r   get_route_io_data_types  s    
z$ApiNamespace.get_route_io_data_typesc                 C   sZ   t  }|j|j|jfD ]>}t|s*t|r6|}|j}qt|sFt|r|}|	| q|S )zV
        Given a route, returns a set of its argument/result/error datatypes.
        )
rZ   arg_data_typeresult_data_typeerror_data_typer   r   r1   r   r
   rW   )r   rL   r:   ZdtypeZdata_list_typeZdata_user_typer   r   r   rf     s    z.ApiNamespace.get_route_io_data_types_for_routec                 C   sr   g }| j  D ]N\}}|r"|js"q|s:|js:|js:|js:q|sR|jsR|jsR|jsRq|| q|jdd d |S )a  
        Returns a list of Namespace objects. A namespace is a member of this
        list if it is imported by the current namespace and a data type is
        referenced from it. Namespaces are in ASCII order by name.

        Args:
            must_have_imported_data_type (bool): If true, result does not
                include namespaces that were not imported for data types.
            consider_annotations (bool): If false, result does not include
                namespaces that were only imported for annotations
            consider_annotation_types (bool): If false, result does not
                include namespaces that were only imported for annotation types.

        Returns:
            List[Namespace]: A list of imported namespaces.
        c                 S   s   | j S r   r_   nr   r   r   rb   @  rc   z6ApiNamespace.get_imported_namespaces.<locals>.<lambda>rd   )rB   itemsr1   r0   r3   r2   rI   sort)r   Zmust_have_imported_data_typeZconsider_annotationsZconsider_annotation_typesZimported_namespacesZimported_namespacerU   r   r   r   get_imported_namespaces  s.    
z$ApiNamespace.get_imported_namespacesc                 C   sJ   t |  dd d}t }|D ]}|j| kr||j qt |dd dS )a  
        Returns a list of Namespace objects. A namespace is a member of this
        list if it is imported by the current namespace and has a data type
        from it referenced as an argument, result, or error of a route.
        Namespaces are in ASCII order by name.
        c                 S   s   | j S r   r_   r`   r   r   r   rb   L  rc   zBApiNamespace.get_namespaces_imported_by_route_io.<locals>.<lambda>rd   c                 S   s   | j S r   r_   rk   r   r   r   rb   Q  rc   )r$   rg   rZ   r(   rW   )r   Znamespace_data_typesZreferenced_namespacesr1   r   r   r   #get_namespaces_imported_by_route_ioC  s    
z0ApiNamespace.get_namespaces_imported_by_route_ioc                 C   sL   | j jdd d | jjdd d | jjdd d | jjdd d dS )zQ
        Alphabetizes routes to make route declaration order irrelevant.
        c                 S   s   | j S r   r_   )rL   r   r   r   rb   X  rc   z(ApiNamespace.normalize.<locals>.<lambda>rd   c                 S   s   | j S r   r_   rX   r   r   r   rb   Y  rc   c                 S   s   | j S r   r_   r\   r   r   r   rb   Z  rc   c                 S   s   | j S r   r_   )r2   r   r   r   rb   [  rc   N)r7   rn   r:   r<   r>   r4   r   r   r   r'   S  s    zApiNamespace.normalizec                 C   s   t d| jS )NzApiNamespace({!r}))strformatr"   r4   r   r   r   __repr__]  s    zApiNamespace.__repr__N)FFFF)FFF)r+   r,   r-   r.   r    rH   rM   rO   rQ   rR   rS   rV   r[   r^   rg   rf   ro   rp   r'   rs   r   r   r   r   r   c   s0   	    
"   
&
c                   @   sp   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S )ApiRoutez%
    Represents an API endpoint.
    c                 C   s@   || _ || _|| _d| _d| _d| _d| _d| _d| _d| _	dS )z
        :param str name: Designated name of the endpoint.
        :param int version: Designated version of the endpoint.
        :param ast_node: Raw route definition from the parser.
        N)
r"   r   	_ast_node
deprecatedraw_docr6   rh   ri   rj   attrs)r   r"   r   Zast_noder   r   r   r    g  s    
zApiRoute.__init__c                 C   s2   || _ || _t|| _|| _|| _|| _|| _dS )a]  
        Converts a forward reference definition of a route into a full
        definition.

        :param DeprecationInfo deprecated: Set if this route is deprecated.
        :param str doc: Description of the endpoint.
        :type arg_data_type: :class:`stone.data_type.DataType`
        :type result_data_type: :class:`stone.data_type.DataType`
        :type error_data_type: :class:`stone.data_type.DataType`
        :param dict attrs: Map of string keys to values that are either int,
            float, bool, str, or None. These are the route attributes assigned
            in the spec.
        N)rv   rw   r	   r6   rh   ri   rj   rx   )r   rv   r6   rh   ri   rj   rx   r   r   r   set_attributes~  s    
zApiRoute.set_attributesc                 C   s$   | j dkr| jS d| j| j S dS )z
        Get user-friendly representation of the route.

        :return: Route name with version suffix. The version suffix is omitted for version 1.
        r   z{}:{}N)r   r"   rr   r4   r   r   r   name_with_version  s    
zApiRoute.name_with_versionc                 C   s   d |  S )NzApiRoute({}))rr   rz   r4   r   r   r   rs     s    zApiRoute.__repr__c                 C   sp   t |tstd|t |ts0td||j|jk sH|j|jk rLdS |j|jksd|j|jkrhdS dS d S )Nz Expected ApiRoute for object: {}r   r   )rD   rt   	TypeErrorrr   r"   r   )r   lhsrhsr   r   r   _compare  s    

zApiRoute._comparec                 C   s   |  | |dk S Nr   r   r   otherr   r   r   __lt__  s    zApiRoute.__lt__c                 C   s   |  | |dkS r   r   r   r   r   r   __gt__  s    zApiRoute.__gt__c                 C   s   |  | |dkS r   r   r   r   r   r   __eq__  s    zApiRoute.__eq__c                 C   s   |  | |dkS r   r   r   r   r   r   __le__  s    zApiRoute.__le__c                 C   s   |  | |dkS r   r   r   r   r   r   __ge__  s    zApiRoute.__ge__c                 C   s   |  | |dkS r   r   r   r   r   r   __ne__  s    zApiRoute.__ne__c                 C   s4   t | j| j| j| j| j| j| j| j| j	t
| jf
S r   )hashr"   r   ru   rv   rw   r6   rh   ri   rj   idrx   r4   r   r   r   __hash__  s    zApiRoute.__hash__N)r+   r,   r-   r.   r    ry   rz   rs   r   r   r   r   r   r   r   r   r   r   r   r   rt   b  s   rt   c                   @   s   e Zd ZdddZdS )DeprecationInfoNc                 C   s(   |dkst |tstt||| _dS )zR
        :param ApiRoute by: The route that replaces this deprecated one.
        N)rD   rt   r)   reprby)r   r   r   r   r   r      s    zDeprecationInfo.__init__)N)r+   r,   r-   r    r   r   r   r   r     s   r   c                   @   s   e Zd ZdZdd ZdS )rJ   zD
    Represents routes of different versions for a common name.
    c                 C   s
   i | _ dS )zR
        :param at_version: The dict mapping a version number to a route.
        N)rK   r4   r   r   r   r      s    zApiRoutesByVersion.__init__Nr5   r   r   r   r   rJ     s   rJ   )(
__future__r   r   r   r   collectionsr   Zdistutils.versionr   rE   r:   r	   r
   r   r   r   Z_MYPYtypingr   r   r   r   r   ZDataTypeListr   r   r   Zstone.frontend.astr   PY3DictTextZNamespaceDictobjectr   r/   r   rt   r   rJ   r   r   r   r   <module>   s(   (,  i
