B
    nb\%                 @   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
mZmZ ddlmZm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S ).zMiscellaneous utilities    N)is_text_stringgetcwd)get_home_dirdebug_printc             C   s@   t | d dkr<x(dD ] }t | | rt| |  qW dS )zCEventually remove .pyc and .pyo files associated to a Python script   z.py)coN)ospsplitextexistsosremove)fnameZending r   0lib/python3.7/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_file/   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   onerror9   s    
r!   N  c          
   C   s|   ddl }xnzZy&| |j|j|j}|d| f W n, |jk
r^ } z| d7 } W dd}~X Y nX P W d|  d}X q
W | 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_portI   s    
r&   c                s   dkr6dddddddd	d
ddddddddddddg |dkrJddddg} fdd}d}d}t | rxt| D ]z\}}}x&|dd D ]}	|	|kr||	 qW |dkst ||krtx0|D ](}
|t ||
\}}||7 }||7 }qW qtW n|| \}}||7 }||7 }||fS )zReturn number of source code lines for all filenames in subdirectories
    of *path* with names ending with *extensions*
    Directory names *excluded_dirnames* will be ignoredNz.pyz.pywz.ipyz.enamlz.cz.hz.cppz.hppz.inc.z.hhz.hxxz.ccz.cxxz.clz.fz.forz.f77z.f90z.f95z.f2kZbuildZdistz.hgz.svnc          	      sP   d\}}t | d  krHd}t| d}t|   }W d Q R X ||fS )N)r   r   r   rb)r	   r
   openlenreadstrip
splitlines)r   dfilesdlinesZtextfile)
extensionsr   r   get_filelinesg   s    z"count_lines.<locals>.get_filelinesr   )r	   isdirr   walkr   dirnamejoin)r   r0   Zexcluded_dirnamesr1   linesfilesdirpathZdirnames	filenamesdr   r.   r/   r   )r0   r   count_lines]   s0    

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    

rC   c             C   s   ddl }|d| S )zReturn error matchr   Nz  File "(.*)", line (\d*))rematch)textrD   r   r   r   get_error_match   s    rG   c              C   s    t jdd} | drd} | S )z Return path to Python executablezpythonw.exez
python.exez
spyder.exe)sys
executablerB   rA   )rI   r   r   r   get_python_executable   s    
rJ   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 k	rZd|f }t |d }|d k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   )rP   rQ   rR   r   )rP   rQ   r   monkeypatch_method   s    rS   c             C   s   t | o| dS )zIs it a valid Python script?)z.pyz.pywz.ipy)r	   isfilerA   )r   r   r   r   is_python_script   s    rU   c             C   s   t t | tjS )zReturn absolute parent dir)r	   abspathr5   r   pardir)r   r   r   r   	abspardir   s    rX   c          	   C   st   t t | }t|dkrpt |s.t|S x@| D ].}t t ||t|d d s4t|S q4W t |S dS )z,Return common path for all paths in pathlistr   N)r	   normpathcommonprefixr*   r2   rX   r5   rV   )pathlistcommonr   r   r   r   get_common_path   s    

"r]   Fc       	      C   s   t | tsttdd | D s$td}tj|}tj|d k	r|stj| }|sxLt	| d d  D ]8\}}|
|d rh||d |d | tj | |< qhW | d|  q|tj | |d}|S n |s| |d |  nd|iS d S )Nc             S   s   g | ]}t |qS r   )r   ).0r   r   r   r   
<listcomp>   s    z.add_pathlist_to_PYTHONPATH.<locals>.<listcomp>
PYTHONPATH=zOLD_PYTHONPATH=)r`   ZOLD_PYTHONPATH)
isinstancelistAssertionErrorallr   pathsepr5   environget	enumerate
startswithrB   append)	envr[   Zdrop_envZ
ipyconsoleZpypathZpathstrZ
old_pypathindexvarr   r   r   add_pathlist_to_PYTHONPATH   s$    

ro   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                 sF   t | t | }| kr&| | |< t dkr> jdd  | S )Nd   F)Zlast)strr*   popitem)argskwargskey)cacheobjr   r   memoizer  s    zmemoize.<locals>.memoizer)rv   	functoolswraps)rw   rx   r   )rv   rw   r   memoize   s    	
	r{   c               C   s*   yt  S  tk
r$   td t S X dS )zSafe 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   OSErrorr   r   r   r   r   r   getcwd_or_home  s
    r}   c          
   C   s<   yt |  W n( t jk
r6 } zt|S d}~X Y nX dS )zy
    Return None if the pattern is a valid regular expression or
    a string describing why the pattern is invalid.
    N)rD   compiler$   rq   )patterner   r   r   regexp_error_msg  s
    r   )r"   )NN)FF)"__doc__codecsry   r   os.pathr   r	   rD   rH   r   Zspyder.py3compatr   r   Zspyder.config.baser   r   r   r   r   r   r!   r&   r;   rC   rG   rJ   rS   rU   rX   r]   ro   r{   r}   r   r   r   r   r   <module>   s8   		


%	 
