B
    ›³ëb:!  ã               @   s”   d 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 e 	dej
¡Ze 	dej
¡Zddd„Zd	d
„ Zdd„ Zddd„ZdgZeedeeddZdS )aÍ  Dependency scanner for Python code.

One important note about the design is that this does not take any dependencies
upon packages or binaries in the Python installation unless they are listed in
PYTHONPATH. To do otherwise would have required code to determine where the
Python installation is, which is outside of the scope of a scanner like this.
If consumers want to pick up dependencies upon these packages, they must put
those directories in PYTHONPATH.

é    Né   )ÚScannerBasez#^\s*from\s+([^\s]+)\s+import\s+(.*)z^\s*import\s+([^\s]+)c             C   s6   | d   dd¡ tj¡}|r.| |d jj¡ t|ƒS )z(Retrieves a tuple with all search paths.ZENVZ
PYTHONPATHÚ r   )ÚgetÚsplitÚosÚpathsepÚappendÚdirÚabspathÚtuple)Úenvr
   ÚtargetÚsourceZargumentÚpaths© r   ú3lib/python3.7/site-packages/SCons/Scanner/Python.pyÚpath_function0   s    r   c             C   s¤   |   ¡ }g }t |¡}|rvxZ|D ]R}dd„ |d  d¡D ƒ}|d  ¡ }t|ƒdkr`|d |d< | |d |f¡ q W t |¡}|r x|D ]}| |df¡ qŠW |S )an  Scans the node for all imports.

    Returns a list of tuples. Each tuple has two elements:
        1. The main import (e.g. module, module.file, module.module2)
        2. Additional optional imports that could be functions or files
            in the case of a "from X import Y" statement. In the case of a
            normal "import" statement, this is None.
    c             S   s   g | ]}|  ¡ ‘qS r   )Ústrip)Ú.0Úir   r   r   ú
<listcomp>F   s    z&find_include_names.<locals>.<listcomp>r   ú,éÿÿÿÿr   N)Zget_text_contentsÚfrom_creÚfindallr   Úlenr	   Ú
import_cre)ÚnodeÚtextZall_matchesZmatchesÚmatchÚimportsZlast_import_splitr   r   r   Úfind_include_names8   s    	



r"   c             C   s\   xV|D ]N}|g}t jj | d |¡}|r2|d|fS t jj | d |¡}|r|d|fS qW dS )a¯  
    Finds the specified import in the various search paths.
    For an import of "p", it could either result in a file named p.py or
    p/__init__.py. We can't do two consecutive searches for p then p.py
    because the first search could return a result that is lower in the
    search_paths precedence order. As a result, it is safest to iterate over
    search_paths and check whether p or p.py exists in each path. This allows
    us to cleanly respect the precedence order.

    If the import is found, returns a tuple containing:
        1. Discovered dependency node (e.g. p/__init__.py or p.py)
        2. True if the import was a package, False if the import was a module.
        3. The Dir node in search_paths that the import is relative to.
    If the import is not found, returns a tuple containing (None, False, None).
    Callers should check for failure by checking whether the first entry in the
    tuple is not None.
    z/__init__.pyTz.pyF)NFN)ÚSConsÚNodeÚFSÚ	find_file)Zimport_pathÚsearch_pathsÚsearch_pathr   r   r   r   r   Úfind_importX   s    

r)   r   c                sÞ  | j d k	r| j }nt| ƒ}tttjj|ƒƒ| _ g }t|ƒr@|ƒ }x’|D ]ˆ\}}| d¡}|r°| 	d¡}t
|ƒt
|ƒ d }	|  ¡ }
xt d |	¡D ]}|
 ¡ }
q”W |
g}|}n‡ fdd„|D ƒ}|}|sÌqHdd„ | d¡D ƒ}d }d }|sö|d }n2td |¡|ƒ\}}}|r(| |¡ |r(|j}|rf|rfx0|D ](}t||gƒ\}}}|r:| |¡ q:W |rH|sH|}x^tt
|ƒƒD ]N}d |d |d … dg ¡}tjj ||g¡}|r€||kr€| |¡ q€W qHW t|ƒS )	NÚ.r   c                s   g | ]}ˆ   |¡‘qS r   )ZDir)r   Úp)r   r   r   r   —   s    zscan.<locals>.<listcomp>c             S   s   g | ]}|r|‘qS r   r   )r   Úxr   r   r   r   Ÿ   s    r   ú/z__init__.py)Úincludesr"   ÚlistÚmapr#   ZUtilZsilent_internÚcallableÚ
startswithÚlstripr   Zget_dirÚ	itertoolsÚrepeatZupr   r)   Újoinr	   r
   Úranger$   r%   r&   Úsorted)r   r   Úpathr.   ZnodesÚmoduler!   Zis_relativeZmodule_lstrippedZnum_parentsZcurrent_dirr   r'   Zsearch_stringZmodule_componentsZpackage_dirZhit_dirZimport_nodeÚis_dirÚ_Zimport_dirsZ	init_pathZ	init_noder   )r   r   Úscanz   sZ    





r=   z.pyÚPythonScannerT)ÚnameZskeysr   Ú	recursive)NNNN)r   )Ú__doc__r4   r   ÚreZSCons.Node.FSr#   Z
SCons.Utilr   r   ÚcompileÚMr   r   r   r"   r)   r=   ZPythonSuffixesr>   r   r   r   r   Ú<module>!   s&   
 "
Q