B
    A!p\@0                 @   s   d Z ddlmZ ddlZddl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 d
d Zdd ZdefddZG dd dZG dd deejZG dd dZeddfddZdS )z{
Visitor doing some postprocessing on the astroid tree.
Try to resolve definitions (namespace) dictionary, relationship...
    )print_functionN)bases)
exceptions)manager)modutils)node_classes)utilsc             C   s   dS )z@Handler used by interfaces to handle suspicious interface nodes.T )_r	   r	   9lib/python3.7/site-packages/pylint/pyreverse/inspector.py_iface_hdlr   s    r   c          
   C   sn   t d|  y| |S  tjk
r@ } zt | W d d }~X Y n* tk
rh } zt  W d d }~X Y nX d S )Nzparsing %s...)printr   ZAstroidBuildingException	Exception	traceback	print_exc)funcmodnameexcr	   r	   r   _astroid_wrapper$   s    r   Tc             c   s   yt | dd }W n tjk
r.   dS X |sD| | k	rDdS t }d}xBt|D ]4}|t	j
krnd}qZ||krZ||rZ|| |V  qZW |rt dS )zEReturn an iterator on interfaces implemented by the given class node.Z__implements__r   NFT)r   ZInstancegetattrr   ZNotFoundErrorframesetr   Zunpack_inferastroidZUninferableaddInferenceError)nodeZheritedZhandler_func
implementsfoundZmissingZifacer	   r	   r   
interfaces.   s"    


r   c               @   s,   e Zd ZdZd
ddZdddZdd Zd	S )IdGeneratorMixInz1Mixin adding the ability to generate integer uid.r   c             C   s
   || _ d S )N)id_count)selfstart_valuer	   r	   r   __init__G   s    zIdGeneratorMixIn.__init__c             C   s
   || _ dS )zinit the id counter
        N)r    )r!   r"   r	   r	   r   init_counterJ   s    zIdGeneratorMixIn.init_counterc             C   s   |  j d7  _ | j S )z"generate a new identifier
           )r    )r!   r	   r	   r   generate_idO   s    zIdGeneratorMixIn.generate_idN)r   )r   )__name__
__module____qualname____doc__r#   r$   r&   r	   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
d Zdd Zdd Z	eZ
eZeZe	Zdd Zedd Zdd Zdd Zdd Zdd ZdS )Linkera  Walk on the project tree and resolve relationships.

    According to options the following attributes may be
    added to visited nodes:

    * uid,
      a unique identifier for the node (on astroid.Project, astroid.Module,
      astroid.Class and astroid.locals_type). Only if the linker
      has been instantiated with tag=True parameter (False by default).

    * Function
      a mapping from locals names to their bounded value, which may be a
      constant like a string or an integer, or an astroid node
      (on astroid.Module, astroid.Class and astroid.Function).

    * instance_attrs_type
      as locals_type but for klass member attributes (only on astroid.Class)

    * implements,
      list of implemented interface _objects_ (only on astroid.Class nodes)
    r   Fc             C   s,   t |  tj|  || _|| _|| _d S )N)r   r#   r   LocalsVisitorinherited_interfacestagproject)r!   r/   r-   r.   r	   r	   r   r#   m   s
    
zLinker.__init__c             C   s.   | j r|  |_x|jD ]}| | qW dS )zbvisit a pyreverse.utils.Project node

         * optionally tag the node with a unique id
        N)r.   r&   uidmodulesvisit)r!   r   moduler	   r	   r   visit_projectw   s    
zLinker.visit_projectc             C   s0   | j r|  |_x| D ]}| | qW dS )z[visit an astroid.Package node

         * optionally tag the node with a unique id
        N)r.   r&   r0   valuesr2   )r!   r   Zsubelmtr	   r	   r   visit_package   s    
zLinker.visit_packagec             C   s4   t |drdS tt|_g |_| jr0|  |_dS )zvisit an astroid.Module node

         * set the locals_type mapping
         * set the depends mapping
         * optionally tag the node with a unique id
        locals_typeN)	hasattrcollectionsdefaultdictlistr7   dependsr.   r&   r0   )r!   r   r	   r	   r   visit_module   s    
zLinker.visit_modulec             C   s   t |drdS tt|_| jr*|  |_x0|jddD ] }t	|dg }|
| ||_q8W tt|_x,|j D ]}x|D ]}| || q~W qtW ytt|| j|_W n tjk
r   d|_Y nX dS )zvisit an astroid.Class node

         * set the locals_type and instance_attrs_type mappings
         * set the implements list and build it
         * optionally tag the node with a unique id
        r7   NF)Zrecursspecializationsr	   )r8   r9   r:   r;   r7   r.   r&   r0   Z	ancestorsr   appendr>   instance_attrs_typeZinstance_attrsr5   handle_assignattr_typer   r-   r   r   r   )r!   r   Zbaseobjr>   ZassignattrsZ
assignattrr	   r	   r   visit_classdef   s"    




zLinker.visit_classdefc             C   s.   t |drdS tt|_| jr*|  |_dS )zvisit an astroid.Function node

         * set the locals_type mapping
         * optionally tag the node with a unique id
        r7   N)r8   r9   r:   r;   r7   r.   r&   r0   )r!   r   r	   r	   r   visit_functiondef   s
    
zLinker.visit_functiondefc             C   s   t |drdS d|_|j| kr,| }n| }yxt |dszt|tjrX| | n"t|tj	rp| 
| n
| | |j|j }t| }tt||B |j|j< W n tjk
r   Y nX dS )zEvisit an astroid.AssignName node

        handle locals_type
        _handledNTr7   )r8   rD   namer   root
isinstancer   ZClassDefrB   ZFunctionDefrC   r=   r7   r   inferr;   r   )r!   r   r   currentr5   r	   r	   r   visit_assignname   s$    



zLinker.visit_assignnamec             C   sP   y4t |  }t |j| j }t||B |j| j< W n tjk
rJ   Y nX dS )zNhandle an astroid.assignattr node

        handle instance_attrs_type
        N)r   rH   r@   Zattrnamer;   r   r   )r   parentr5   rI   r	   r	   r   rA      s    zLinker.handle_assignattr_typec             C   s@   |  j}x0|jD ]&}t|d |}| ||d | qW dS )zJvisit an astroid.Import node

        resolve module dependencies
        r   N)rF   filenamesr   is_relative_imported_module)r!   r   context_filerE   relativer	   r	   r   visit_import   s    
zLinker.visit_importc          	   C   s   |j }| j}|dk	r&t||}nd}xx|jD ]n}|d dkrDq2d||d f }|ddkryt||}W n tk
r   w2Y nX ||kr2| 	||| q2W dS )zNvisit an astroid.ImportFrom node

        resolve module dependencies
        NFr   *z%s.%s.)
r   rF   rL   r   rN   rM   findZget_module_partImportErrorrO   )r!   r   basenamerP   rQ   rE   fullnamer	   r	   r   visit_importfrom   s     
zLinker.visit_importfromc             C   s2   t j| jj}||krdS t||fr.dS dS )z9return true if the module should be added to dependenciesr   r%   )ospathdirnamer/   r   Zis_standard_module)r!   context_namemod_pathZpackage_dirr	   r	   r   compute_module  s    zLinker.compute_modulec             C   sj   |  }|j}|r2dd|ddd |f }| ||rft|dsNg |_|j}||krf|| dS )z7Notify an imported module, used to analyze dependenciesz%s.%srT   NrU   r<   )rF   rE   joinsplitr`   r8   r<   r?   )r!   r   r_   rQ   r3   r^   Z	mod_pathsr	   r	   r   rO   "  s     
zLinker._imported_moduleN)r   F)r'   r(   r)   r*   r#   r4   r6   r=   rB   rC   Zlink_projectZlink_moduleZ
link_classZlink_functionrJ   staticmethodrA   rR   rZ   r`   rO   r	   r	   r	   r   r+   V   s"   



"
	r+   c               @   s:   e Zd ZdZdddZdd Zdd Zd	d
 Zdd ZdS )Projectz,a project handle a set of modules / packages c             C   sN   || _ d | _g | _i | _| jj| _| jj| _| jj| _| jj| _| jj| _d S )N)	rE   r\   r1   locals__getitem____iter__r5   keysitems)r!   rE   r	   r	   r   r#   4  s    



zProject.__init__c             C   s   || j |j< | j| d S )N)rf   rE   r1   r?   )r!   r   r	   r	   r   
add_module?  s    zProject.add_modulec             C   s
   | j | S )N)rf   )r!   rE   r	   r	   r   
get_moduleC  s    zProject.get_modulec             C   s   | j S )N)r1   )r!   r	   r	   r   get_childrenF  s    zProject.get_childrenc             C   s   d| j t| t| jf S )Nz<Project %r at %s (%s modules)>)rE   idlenr1   )r!   r	   r	   r   __repr__I  s    zProject.__repr__N)re   )	r'   r(   r)   r*   r#   rk   rl   rm   rp   r	   r	   r	   r   rd   1  s   
rd   zno name)ZCVSc       
      C   s   t  }t|}x| D ]}tj|s8t|d}n tj	|rTtj
|d}n|}||j|}|dkrnq|jpx|j|_|| |j}	|jr|ddkrxHttj|j|D ].}||j|}|dks|j|	krq|| qW qW |S )z0return a Project from a list of files or modulesrT   z__init__.pyNr#   rU   )r   ZAstroidManagerrd   r[   r\   existsr   Zfile_from_modpathrb   isdirra   Zast_from_filerL   rk   rE   packagerV   Zget_module_filesr]   )
filesZfunc_wrapperZproject_nameZ
black_listZastroid_managerr/   Z	somethingZfpathZastZ	base_namer	   r	   r   project_from_filesQ  s,    

ru   )r*   Z
__future__r   r9   r[   r   r   r   r   r   r   r   Zpylint.pyreverser   r   r   r   r   r,   r+   rd   ru   r	   r	   r	   r   <module>   s&   
 \!