a
     ³Ša}(  ã                   @   s  d Z ddlZddlZddl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mZ ddlmZ e e¡Zdd„ Zdd„ Zd	d
„ Zdd„ Zdd„ Zd-dd„Zd.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#d$„Z!d%d&„ Z"d'd(„ Z#d)d*„ Z$d+d,„ Z%dS )0zMiscellaneous utilitiesé    N)Úis_text_stringÚgetcwd)Úget_home_dirc                 C   s<   t  | ¡d dkr8dD ] }t  | | ¡rt | | ¡ qdS )zCEventually remove .pyc and .pyo files associated to a Python scripté   ú.py)ÚcÚoN)ÚospÚsplitextÚexistsÚosÚremove)ÚfnameZending© r   ú0lib/python3.9/site-packages/spyder/utils/misc.pyÚ__remove_pyc_pyo   s    r   c                 C   s   t  | |¡ t| ƒ dS )zt
    Rename file from *source* to *dest*
    If file is a Python script, also rename .pyc and .pyo files if any
    N)r   Úrenamer   )ÚsourceÚdestr   r   r   Úrename_file!   s    r   c                 C   s   t  | ¡ t| ƒ dS )zd
    Remove file *fname*
    If file is a Python script, also rename .pyc and .pyo files if any
    N)r   r   r   ©r   r   r   r   Úremove_file*   s    
r   c                 C   s    ddl }| | |¡ t| ƒ dS )zr
    Move file from *source* to *dest*
    If file is a Python script, also rename .pyc and .pyo files if any
    r   N)ÚshutilÚcopyr   )r   r   r   r   r   r   Ú	move_file3   s    r   c                 C   s,   t  |t j¡s&t  |tj¡ | |ƒ n‚ dS )a  Error handler for `shutil.rmtree`.

    If the error is due to an access error (read-only file), it
    attempts to add write permission and then retries.
    If the error is for another reason, it re-raises the error.

    Usage: `shutil.rmtree(path, onerror=onerror)N)r   ÚaccessÚW_OKÚchmodÚstatÚS_IWUSR)ZfunctionÚpathÚexcinfor   r   r   Úonerror=   s    
r"   é N  c              
   C   s”   ddl }zvz&|  |j|j|j¡}| d| f¡ W n. |jy^ } z| d7 } W Y d}~nd}~0 0 W | ¡  d}qW | ¡  d}q| ¡  d}0 q| S )zFind and return a non used portr   Nz	127.0.0.1r   )ÚsocketZAF_INETZSOCK_STREAMZIPPROTO_TCPZbindÚerrorÚclose)Zdefault_portr$   ZsockZ_msgr   r   r   Úselect_portM   s$    þýÿr'   c                    sâ   ˆ du rg d¢‰ |du r g d¢}‡ fdd„}d}d}t  | ¡r¾t | ¡D ]r\}}}|dd… D ]}	|	|v r^| |	¡ q^|du sŒt  |¡|vrH|D ](}
|t  ||
¡ƒ\}}||7 }||7 }qqHn|| ƒ\}}||7 }||7 }||fS )z°Return number of source code lines for all filenames in subdirectories
    of *path* with names ending with *extensions*
    Directory names *excluded_dirnames* will be ignoredN)r   ú.pywú.ipyz.enamlz.cz.hz.cppz.hppz.incÚ.z.hhz.hxxz.ccz.cxxz.clz.fz.forz.f77z.f90z.f95z.f2kz.f03z.f08)ZbuildZdistz.hgz.svnc                    sd   d\}}t  | ¡d ˆ v r\d}t| dƒ$}t| ¡  ¡  ¡ ƒ}W d   ƒ n1 sR0    Y  ||fS )N)r   r   r   Úrb)r	   r
   ÚopenÚlenÚreadÚstripÚ
splitlines)r    ÚdfilesÚdlinesZtextfile©Ú
extensionsr   r   Úget_filelinesl   s    2z"count_lines.<locals>.get_filelinesr   )r	   Úisdirr   Úwalkr   ÚdirnameÚjoin)r    r4   Zexcluded_dirnamesr5   ÚlinesÚfilesÚdirpathZdirnamesÚ	filenamesÚdr   r1   r2   r   r3   r   Úcount_linesa   s.    
ÿr?   c                 C   sF   t jdkrB|  d¡r*|  d¡s*| dd… } |  dd¡} |  dd¡} | S )	av  Remove backslashes in *path*

    For Windows platforms only.
    Returns the path unchanged on other platforms.

    This is especially useful when formatting path strings on
    Windows platforms for which folder paths may contain backslashes
    and provoke unicode decoding errors in Python 3 (or in Python 2
    when future 'unicode_literals' symbol has been imported).Úntú\z\\Néÿÿÿÿú/z/'z\')r   ÚnameÚendswithÚreplace©r    r   r   r   Úremove_backslashes‡   s    

rH   c                 C   s   ddl }| d| ¡S )zReturn error matchr   Nz  File "(.*)", line (\d*))ÚreÚmatch)ÚtextrI   r   r   r   Úget_error_match›   s    rL   c                  C   s    t j dd¡} |  d¡rd} | S )z Return path to Python executablezpythonw.exez
python.exez
spyder.exe)ÚsysÚ
executablerF   rE   )rN   r   r   r   Úget_python_executable¡   s    
rO   c                    s   ‡ ‡fdd„}|S )aB  
    Add the decorated method to the given class; replace as needed.

    If the named method already exists on the given class, it will
    be replaced, and a reference to the old method is created as
    cls._old<patch_name><name>. If the "_old_<patch_name>_<name>" attribute
    already exists, KeyError is raised.
    c                    sj   | j }tˆ |d ƒ}|d urZdˆ|f }tˆ |d ƒ}|d u rHtˆ ||ƒ ntdˆ j |f ƒ‚tˆ || ƒ | S )Nz
_old_%s_%sz%s.%s already exists.)Ú__name__ÚgetattrÚsetattrÚKeyError)Úfuncr   Zold_funcZold_refZold_attr©ÚclsÚ
patch_namer   r   Ú	decorator·   s    ÿz%monkeypatch_method.<locals>.decoratorr   )rV   rW   rX   r   rU   r   Úmonkeypatch_methodª   s    rY   c                 C   s   t  | ¡o|  d¡S )zIs it a valid Python script?)r   r(   r)   )r	   ÚisfilerE   r   r   r   r   Úis_python_scriptÉ   s    r[   c                 C   s   t  t  | tj¡¡S )zReturn absolute parent dir)r	   Úabspathr9   r   ÚpardirrG   r   r   r   Ú	abspardirÎ   s    r^   c              	   C   st   t  t  | ¡¡}t|ƒdkrpt  |¡s.t|ƒS | D ]2}t  t  ||t|ƒd d… ¡¡s2t|ƒ  S q2t  |¡S dS )z,Return common path for all paths in pathlistr   N)r	   ÚnormpathÚcommonprefixr-   r6   r^   r9   r\   )ÚpathlistÚcommonr    r   r   r   Úget_common_pathÓ   s    
"rc   Tc                 C   sš   t | tƒsJ ‚tdd„ | D ƒƒs$J ‚d}tj |¡}|s„t| dd… ƒD ]8\}}| |d ¡rH| |d |d | tj ¡| |< qHn|  	|d | ¡ dS )aÜ  
    Add a PYTHONPATH entry to a list of environment variables.

    This allows to extend the environment of an external process
    created with QProcess with our additions to PYTHONPATH.

    Parameters
    ----------
    env: list
        List of environment variables in the format of
        QProcessEnvironment.
    pathlist: list
        List of paths to add to PYTHONPATH
    drop_env: bool
        Whether to drop PYTHONPATH previously found in the environment.
    c                 S   s   g | ]}t |ƒ‘qS r   )r   )Ú.0r    r   r   r   Ú
<listcomp>õ   ó    z.add_pathlist_to_PYTHONPATH.<locals>.<listcomp>Z
PYTHONPATHNú=)
Ú
isinstanceÚlistÚallr   Úpathsepr9   Ú	enumerateÚ
startswithrF   Úappend)Úenvra   Zdrop_envZpypathZpathstrÚindexÚvarr   r   r   Úadd_pathlist_to_PYTHONPATHâ   s    þrr   c                    s&   i  ‰ ˆ_ t ˆ¡‡ ‡fdd„ƒ}|S )zí
    Memoize objects to trade memory for execution speed

    Use a limited size cache to store the value, which takes into account
    The calling args and kwargs

    See https://wiki.python.org/moin/PythonDecoratorLibrary#Memoize
    c                     sJ   t | ƒt |ƒ }|ˆ vr*ˆ| i |¤Žˆ |< tˆ ƒdkrBˆ jdd ˆ | S )Néd   F)Zlast)Ústrr-   Úpopitem)ÚargsÚkwargsÚkey©ÚcacheÚobjr   r   Úmemoizer  s    zmemoize.<locals>.memoizer)rz   Ú	functoolsÚwraps)r{   r|   r   ry   r   Úmemoize  s    	
r   c                   C   s0   zt ƒ W S  ty*   t d¡ tƒ  Y S 0 dS )z²Safe version of getcwd that will fallback to home user dir.

    This will catch the error raised when the current working directory
    was removed for an external program.
    zNWARNING: Current working directory was deleted, falling back to home dirertoryN)r   ÚOSErrorÚloggerÚdebugr   r   r   r   r   Úgetcwd_or_home  s
    
rƒ   c              
   C   sB   zt  | ¡ W n. t jy< } zt|ƒW  Y d}~S d}~0 0 dS )zy
    Return None if the pattern is a valid regular expression or
    a string describing why the pattern is invalid.
    N)rI   Úcompiler%   rt   )ÚpatternÚer   r   r   Úregexp_error_msg)  s
    r‡   c              
   C   s¸   t   ¡ }| d¡ t d | |¡¡ z„z0| | |f¡ t d | |¡¡ W W | ¡  dS  t jyœ } z,t d | ||¡¡ W Y d}~W | ¡  dS d}~0 0 W | ¡  n
| ¡  0 dS )z+Verify if `port` is available in `address`.é   z&Attempting to connect to {} on port {}zConnected to {} on port {}Tz&Connection to {} on port {} failed: {}NF)r$   Z
settimeoutr   r‚   ÚformatZconnectr&   r%   )ZaddressZportÚsr†   r   r   r   Úcheck_connection_port5  s&    
ÿúÿþr‹   )r#   )NN)T)&Ú__doc__r}   Zloggingr   Úos.pathr    r	   rI   rM   r   r$   Zspyder.py3compatr   r   Zspyder.config.baser   Z	getLoggerrP   r   r   r   r   r   r"   r'   r?   rH   rL   rO   rY   r[   r^   rc   rr   r   rƒ   r‡   r‹   r   r   r   r   Ú<module>   s<   
		


&	
"