B
    S£†\\  ã               @   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 ddlm	Z	 ddl
mZ ddl
mZ ej d¡rrd	Zd
ZndZdZy(edejdedejdeddhZW n e	k
r¼   eƒ ZY nX ejdkrDe ej ejd¡¡ ye ej ejd¡¡ W nH ek
rB   ye ej ejd¡¡ W n ek
r<   Y nX Y nX e ¡ dkr ej ejd¡Ze e¡ ye ej ejd¡¡ W n ek
rœ   Y nX [ejdkry
ejZW n ek
rÒ   ejZY nX dd„ Ze edƒ¡ ejdkre edƒ¡ eƒ Ze ¡ dkZ e! "ej#d¡Z$G dd„ de%ƒZ&dd„ Z'dd „ Z(e fd!d"„Z)d#d$„ Z*i Z+d%d&„ Z,dPd'd(„Z-dQd)d*„Z.dRd+d,„Z/d-d.„ Z0d/d0„ Z1dSd1d2„Z2dTd3d4„Z3dUd5d6„Z4dVd7d8„Z5dWd9d:„Z6dXd<d=„Z7dYd>d?„Z8d@dA„ Z9dZdBdC„Z:dDdE„ Z;d[dFdG„Z<dHdI„ Z=dJdK„ Z>dLdM„ Z?dNdO„ Z@dS )\aV  Python modules manipulation utility functions.

:type PY_SOURCE_EXTS: tuple(str)
:var PY_SOURCE_EXTS: list of possible python source file extension

:type STD_LIB_DIRS: set of str
:var STD_LIB_DIRS: directories where standard modules are located

:type BUILTIN_MODULES: dict
:var BUILTIN_MODULES: dictionary with builtin module names has key
é    N)Úget_python_lib)ÚDistutilsPlatformErroré   )Úspec)ÚutilÚwin)ÚpyZpyw)ZdllZpyd)r   )ZsoT)Ústandard_libÚprefix)r	   ÚntZdllsZPyPyZlib_pypyÚposixc             C   s"   dt jd d…  }tj t| |¡S )Nzpython%d.%dé   )ÚsysÚversion_infoÚosÚpathÚjoinr
   )r   Zbase_python© r   ú/lib/python3.7/site-packages/astroid/modutils.pyÚ_posix_pathh   s    r   Úlibl        Zlib64ZJythonc               @   s   e Zd ZdZdS )ÚNoSourceFilezaexception raised when we are not able to get a python
    source file for a precompiled file
    N)Ú__name__Ú
__module__Ú__qualname__Ú__doc__r   r   r   r   r   |   s   r   c             C   s   t j t j | ¡¡S )N)r   r   ÚnormcaseÚabspath)r   r   r   r   Ú_normalize_path‚   s    r   c             C   s   t j t j | ¡¡S )N)r   r   ÚrealpathÚ
expanduser)r   r   r   r   Ú_canonicalize_path†   s    r!   c             C   sL   |s,t jdkr| S |  d¡r(| d d… S | S |  d¡\}}}|rH|d S | S )N)é   r   z.pycéÿÿÿÿz	$py.classz.py)r   r   ÚendswithÚ	partition)ÚfilenameZ	is_jythonÚheadZhas_pyclassÚ_r   r   r   Ú_path_from_filenameŠ   s    

r)   c             C   s8   x2| D ]*}||kr|  |¡ q||kr|  |¡ qW dS )z`remove files/directories in the black list

    dirnames/filenames are usually from os.walk
    N)Úremove)Ú	blacklistÚdirnamesÚ	filenamesZnorecursr   r   r   Ú_handle_blacklist—   s
    
r.   c             C   s>   yt |  S  tk
r8   | s$t| ƒS t| ƒ }t | < |S X dS )zabspath with cachingN)Ú_NORM_PATH_CACHEÚKeyErrorr   )r   Úresultr   r   r   Ú_cache_normalize_path¦   s    r2   c             C   s   t |  d¡||ƒS )a"  Load a Python module from its name.

    :type dotted_name: str
    :param dotted_name: python name of a module or package

    :type path: list or None
    :param path:
      optional list of path where the module or package should be
      searched (use sys.path if nothing or None is given)

    :type use_sys: bool
    :param use_sys:
      boolean indicating whether the sys.modules dictionary should be
      used or not


    :raise ImportError: if the module or package is not found

    :rtype: module
    :return: the loaded module
    Ú.)Úload_module_from_modpathÚsplit)Údotted_namer   Úuse_sysr   r   r   Úload_module_from_name´   s    r8   c             C   s4  |r*yt jd | ¡ S  tk
r(   Y nX g }d}xü| D ]ô}| |¡ d |¡}d}t|ƒt| ƒkrrt j |¡}n|r‚t j |¡}|dkr¸t ||¡\}}	}
t 	|||	|
¡}|r¸| 
¡  |rÈt|||ƒ t|ddƒ}|}|sèt |¡rèq8|st|ƒt| ƒkrtdd | t|ƒd… ¡ ƒ‚tj |¡g}q8W |S )a<  Load a python module from its split name.

    :type parts: list(str) or tuple(str)
    :param parts:
      python name of a module or package split on '.'

    :type path: list or None
    :param path:
      optional list of path where the module or package should be
      searched (use sys.path if nothing or None is given)

    :type use_sys: bool
    :param use_sys:
      boolean indicating whether the sys.modules dictionary should be used or not

    :raise ImportError: if the module or package is not found

    :rtype: module
    :return: the loaded module
    r3   NÚ__file__Ú zno module in %s)r   Úmodulesr   r0   ÚappendÚlenÚgetÚimpÚfind_moduleÚload_moduleÚcloseÚsetattrÚgetattrr   Úis_namespaceÚImportErrorr   r   Údirname)Úpartsr   r7   ÚmodpathZ
prevmoduleÚpartZcurnameÚmoduleZmp_fileZmp_filenameZmp_descZ_filer   r   r   r4   Í   s<    


r4   c             C   s   t | |ƒ}t|||ƒS )a  Load a Python module from it's path.

    :type filepath: str
    :param filepath: path to the python module or package

    :type path: list or None
    :param path:
      optional list of path where the module or package should be
      searched (use sys.path if nothing or None is given)

    :type use_sys: bool
    :param use_sys:
      boolean indicating whether the sys.modules dictionary should be
      used or not


    :raise ImportError: if the module or package is not found

    :rtype: module
    :return: the loaded module
    )Úmodpath_from_filer4   )Úfilepathr   r7   Ú	extrapathrI   r   r   r   Úload_module_from_file  s    
rO   c             C   sN   g }xD|D ]<}|  |¡ tj | |¡} t| ƒs
t d |¡¡}|s
dS q
W dS )z2check there are some __init__.py all along the wayr3   FT)r<   r   r   r   Ú	_has_initr   rE   )r   Zmod_pathrI   rJ   Zold_namespacer   r   r   Úcheck_modpath_has_init  s    

rQ   c             C   s’   d}t j |¡}t j | ¡}t j |¡ |¡r2|}t j | ¡}t j |¡ |¡rT|}|rŽt j |¡d }|t|ƒd… }dd„ | t j	¡D ƒS dS )a=  Extracts the relative mod path of the file to import from

    Check if a file is within the passed in path and if so, returns the
    relative mod path from the one passed in.

    If the filename is no in path_to_check, returns None

    Note this function will look for both abs and realpath of the file,
    this allows to find the relative base path even if the file is a
    symlink of a file in the passed in path

    Examples:
        _get_relative_base_path("/a/b/c/d.py", "/a/b") ->  ["c","d"]
        _get_relative_base_path("/a/b/c/d.py", "/dev") ->  None
    Nr   c             S   s   g | ]}|r|‘qS r   r   )Ú.0Úpkgr   r   r   ú
<listcomp>I  s    z+_get_relative_base_path.<locals>.<listcomp>)
r   r   r   r   Ú
startswithr   Úsplitextr=   r5   Úsep)r&   Zpath_to_checkZimportable_pathZabs_filenameZreal_filenameÚ	base_pathZrelative_base_pathr   r   r   Ú_get_relative_base_path,  s    rY   c             C   sê   t j t| ƒ¡} |d k	rzx`t tt|ƒ|¡D ]J}t j |¡}|sBq,t	| |ƒ}|sRq,|||d d… ƒr,||  
d¡| S q,W xRt tttjƒtj¡D ]8}t|ƒ}|s¤q’t	| |ƒ}|s´q’|||d d… ƒr’|S q’W td| d tj¡f ƒ‚d S )Nr#   r3   z"Unable to find module for %s in %sz, 
)r   r   r    r)   Ú	itertoolsÚchainÚmapr!   r   rY   r5   r   r2   rF   r   )r&   rN   Zis_package_cbZpath_r   Z
submodpathrI   r   r   r   Úmodpath_from_file_with_callbackN  s,    

r]   c             C   s   t | |tƒS )ai  given a file path return the corresponding split module's name
    (i.e name of a module or package split on '.')

    :type filename: str
    :param filename: file's path for which we want the module's name

    :type extrapath: dict
    :param extrapath:
      optional extra search path, with path as key and package name for the path
      as value. This is usually useful to handle package split in multiple
      directories using __path__ trick.


    :raise ImportError:
      if the corresponding module's name has not been found

    :rtype: list(str)
    :return: the corresponding split module's name
    )r]   rQ   )r&   rN   r   r   r   rL   k  s    rL   c             C   s   t | ||ƒjS )N)Úfile_info_from_modpathÚlocation)rI   r   Úcontext_filer   r   r   Úfile_from_modpath‚  s    ra   c             C   sŽ   |dk	rt j |¡}n|}| d dkr`ytdg| dd…  ||ƒS  tk
r\   t| ||ƒS X n"| ddgkr‚tjdt jjtj	d	S t| ||ƒS )
aÿ  given a mod path (i.e. split module / package name), return the
    corresponding file, giving priority to source file over precompiled
    file if it exists

    :type modpath: list or tuple
    :param modpath:
      split module's name (i.e name of a module or package split
      on '.')
      (this means explicit relative imports that start with dots have
      empty strings in this list!)

    :type path: list or None
    :param path:
      optional list of path where the module or package should be
      searched (use sys.path if nothing or None is given)

    :type context_file: str or None
    :param context_file:
      context file to consider, necessary if the identifier has been
      introduced using a relative import unresolvable in the actual
      context (i.e. modutils)

    :raise ImportError: if there is no such module in the directory

    :rtype: (str or None, import type)
    :return:
      the path to the module's file or None if it's an integrated
      builtin module such as 'sys'
    Nr   ZxmlZ_xmlplusr   r   r   zos.path)Únamer_   Úmodule_type)
r   r   rG   Ú_spec_from_modpathrF   r   Ú
ModuleSpecr9   r?   Ú	PY_SOURCE)rI   r   r`   Úcontextr   r   r   r^   †  s    r^   c          	   C   s  |   d¡rdS |  d¡}|dk	rH|d tkrHt|ƒdkr@t| ƒ‚|d S d}d}|d dkrt|dk	sltdƒ‚g }d}x$|| dkr˜|d7 }tj |¡}qvW xrt	|t|ƒƒD ]`}yt
|||d … ||d	 W qª tk
r   |tdt|ƒd ƒk rö‚ d |d|… ¡S X qªW | S )
a  given a dotted name return the module part of the name :

    >>> get_module_part('astroid.as_string.dump')
    'astroid.as_string'

    :type dotted_name: str
    :param dotted_name: full name of the identifier we are interested in

    :type context_file: str or None
    :param context_file:
      context file to consider, necessary if the identifier has been
      introduced using a relative import unresolvable in the actual
      context (i.e. modutils)


    :raise ImportError: if there is no such module in the directory

    :rtype: str or None
    :return:
      the module part of the name or None if we have not been able at
      all to import the given name

    XXX: deprecated, since it doesn't handle package precedence over module
    (see #10066)
    zos.pathr3   Nr   r   r:   z.explicit relative import, but no context_file?r   )r   r`   )rU   r5   ÚBUILTIN_MODULESr=   rF   ÚAssertionErrorr   r   rG   Úrangera   Úmaxr   )r6   r`   rH   r   ZstartiÚir   r   r   Úget_module_part¶  s6    


rm   Fc       	      C   s€   g }xvt  | ¡D ]h\}}}||kr$qt|||ƒ |sJd|krJd|dd…< qx,|D ]$}t|ƒrPt j ||¡}| |¡ qPW qW |S )aN  given a package directory return a list of all available python
    module's files in the package and its subpackages

    :type src_directory: str
    :param src_directory:
      path of the directory corresponding to the package

    :type blacklist: list or tuple
    :param blacklist: iterable
      list of files or directories to ignore.

    :type list_all: bool
    :param list_all:
        get files from all paths, including ones without __init__.py

    :rtype: list
    :return:
      the list of all available python module's files in the package and
      its subpackages
    z__init__.pyr   N)r   Úwalkr.   Ú_is_python_filer   r   r<   )	Zsrc_directoryr+   Zlist_allÚfilesÚ	directoryr,   r-   r&   Úsrcr   r   r   Úget_module_filesó  s    
rs   c             C   sn   t j t| ƒ¡} t j | ¡\}}x(tD ] }d||f }t j |¡r&|S q&W |rb|sbt j |¡rb|S t| ƒ‚dS )aš  given a python module's file name return the matching source file
    name (the filename will be returned identically if it's already an
    absolute path to a python source file...)

    :type filename: str
    :param filename: python module's file name


    :raise NoSourceFile: if no source file exists on the file system

    :rtype: str
    :return: the absolute path of the source file if it exists
    z%s.%sN)r   r   r   r)   rV   ÚPY_SOURCE_EXTSÚexistsr   )r&   Zinclude_no_extÚbaseZorig_extÚextÚsource_pathr   r   r   Úget_source_file  s    
ry   c             C   s   t j | ¡d dd… tkS )zN
    rtype: bool
    return: True if the filename is a python source file
    r   N)r   r   rV   rt   )r&   r   r   r   Úis_python_source1  s    rz   c             C   s   |   d¡d } yt| gƒ}W n tk
r0   dS X |dkrFt | ¡ S t|ƒ}| ttƒ¡r`dS |dkrlt	}x|D ]}| t|ƒ¡rrdS qrW dS )aÐ  try to guess if a module is a standard python module (by default,
    see `std_path` parameter's description)

    :type modname: str
    :param modname: name of the module we are interested in

    :type std_path: list(str) or tuple(str)
    :param std_path: list of path considered has standard


    :rtype: bool
    :return:
      true if the module:
      - is located on the path listed in one of the directory in `std_path`
      - is a built-in module
    r3   r   FNT)
r5   ra   rF   r   rE   r   rU   r2   ÚEXT_LIB_DIRÚSTD_LIB_DIRS)ÚmodnameZstd_pathr&   r   r   r   r   Úis_standard_module9  s     
r~   c             C   sn   t j |¡st j |¡}|tjkr&dS y.t |  d¡d |g¡\}}}|rR| ¡  dS  t	k
rh   dS X dS )av  return true if the given module name is relative to the given
    file name

    :type modname: str
    :param modname: name of the module we are interested in

    :type from_file: str
    :param from_file:
      path of the module from which modname has been imported

    :rtype: bool
    :return:
      true if the module has been imported relatively to `from_file`
    Fr3   r   TN)
r   r   ÚisdirrG   r   r?   r@   r5   rB   rF   )r}   Z	from_fileÚstreamr(   r   r   r   Úis_relativea  s    
r   c             C   sô   | st ‚d}|dk	rVyt | |g¡}|j}W qb tk
rR   t | |¡}|j}Y qbX nt | |¡}|jtjjkr¬yt|jƒ}|j	|tjj
dS  tk
r¨   |j	|dS X nD|jtjjkrÆ|j	ddS |jtjjkrðt|jƒ}|j	|tjj
dS |S )zÃgiven a mod path (i.e. split module / package name), return the
    corresponding spec

    this function is used internally, see `file_from_modpath`'s
    documentation for more information
    N)r_   Útype)r_   )ri   r   Ú	find_specr_   rF   r‚   Ú
ModuleTypeÚPY_COMPILEDry   Ú_replacerf   r   Z	C_BUILTINÚPKG_DIRECTORYrP   )rI   r   rg   r_   Z
found_specr   r   r   rd   ‚  s.    


rd   c             C   s    xdD ]}|   |¡rdS qW dS )zkreturn true if the given filename should be considered as a python file

    .pyc and .pyo are ignored
    )z.pyz.soz.pydz.pywTF)r$   )r&   rw   r   r   r   ro   ¥  s    

ro   c             C   sD   t j | d¡}x0td D ]$}t j |d | ¡r|d | S qW dS )z\if the given directory has a valid __init__ file, return its path,
    else return None
    Ú__init__)ZpycZpyor3   N)r   r   r   rt   ru   )rq   Zmod_or_packrw   r   r   r   rP   °  s
    rP   c             C   s   | j tjjkS )N)r‚   r   r„   ZPY_NAMESPACE)Úspecobjr   r   r   rE   »  s    rE   c             C   s   | j tjjkS )N)r‚   r   r„   r‡   )r‰   r   r   r   Úis_directory¿  s    rŠ   )NT)Nr   )NTN)NN)N)NN)NN)N)F)F)N)NN)Ar   r?   r   Úplatformr   rZ   Zdistutils.sysconfigr   Zdistutils.errorsr   Zinterpreter._importr   r   rU   rt   ZPY_COMPILED_EXTSr
   Úexec_prefixr|   Úsetrb   Úaddr   r   Zreal_prefixÚAttributeErrorÚbase_exec_prefixZpython_implementationZ_rootr   Úmaxsizer{   Z	IS_JYTHONÚdictÚfromkeysÚbuiltin_module_namesrh   Ú	Exceptionr   r   r!   r)   r.   r/   r2   r8   r4   rO   rQ   rY   r]   rL   ra   r^   rm   rs   ry   rz   r~   r   rd   ro   rP   rE   rŠ   r   r   r   r   Ú<module>   s˜   



8
"



0
=
%

(!
#