3
dk                 @   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ZddlZddlm	Z	 ddl
Z
ddlj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ZddlmZmZ ddlmZmZmZ dd	lmZ ejd
Z dadbdcgZ!dd Z"ddddZ#dd Z$deddZ%dfddZ&dd Z'd d! Z(d"ej	dfd#d$Z)d%d& Z*d'd( Z+d)d* Z,e, Z-d+d, Z.dgd-d.Z/dhd/d0Z0did1d2Z1d3d4 Z2d5d6 Z3e2Z4e3Z5d7d8 Z6d9d: Z7d;d< Z8d=d> Z9d?d@ Z:dAdB Z;djdCdDZ<dkdEdFZ=dGdHdIdJgZ>dldKdLZ?dmdMdNZ@dndOdPZAdQdR ZBdodSdTZCdUdV ZDdpdWdXZEdYdZ ZFd[d\ ZGdqd]d^ZHejId_d` ZJdS )rz*Miscellaneous file manipulation functions
    N)md5)Path)sleeptime   )loggingconfig__version__   )is_containerznipype.utils.hdr.img.mat.nii.BRIK.HEADc             K   sL   y| j f |S  tk
rF } zt|tr* tt| W Y dd}~X nX dS )z*Raise FileNotFoundError instead of OSErrorN)resolveOSError
isinstanceFileNotFoundErrorstr)pathkwargse r   8/tmp/pip-build-7vycvbft/nipype/nipype/utils/filemanip.py_resolve_with_filenotfound    s    
r   Fc             C   sB   yt | |dS  tk
r    Y nX | j } |s6| j r>t | S | S )N)strict)r   	TypeErrorZabsoluteexists)r   r   r   r   r   path_resolve*   s    r    c             C   s   dddg}t j| }t j| } d}xX|D ]P}t|}t| |kr(| | d j |j kr(| | d }| d|  } P q(W |st j| \} }|| |fS )a1  Split a filename into parts: path, base filename and extension.

    Parameters
    ----------
    fname : str
        file or path name

    Returns
    -------
    pth : str
        base path from fname
    fname : str
        filename from fname, without extension
    ext : str
        file extension from fname

    Examples
    --------
    >>> from nipype.utils.filemanip import split_filename
    >>> pth, fname, ext = split_filename('/home/data/subject.nii.gz')
    >>> pth
    '/home/data'

    >>> fname
    'subject'

    >>> ext
    '.nii.gz'

    z.nii.gzz.tar.gzz
.niml.dsetN)opdirnamebasenamelenlowersplitext)fnameZspecial_extensionspthextZspecial_extZext_lenr   r   r   split_filename:   s     



&r*    Tc             C   s<   t | \}} }|sd}|r$tj|}tj|||  | | S )ar  Manipulates path and name of input filename

    Parameters
    ----------
    fname : string
        A filename (may or may not include path)
    prefix : string
        Characters to prepend to the filename
    suffix : string
        Characters to append to the filename
    newpath : string
        Path to replace the path of the input fname
    use_ext : boolean
        If True (default), appends the extension of the original file
        to the output name.

    Returns
    -------
    Absolute path of the modified filename

    >>> from nipype.utils.filemanip import fname_presuffix
    >>> fname = 'foo.nii.gz'
    >>> fname_presuffix(fname,'pre','post','/tmp')
    '/tmp/prefoopost.nii.gz'

    >>> from nipype.interfaces.base import Undefined
    >>> fname_presuffix(fname, 'pre', 'post', Undefined) ==             fname_presuffix(fname, 'pre', 'post')
    True

    r+   )r*   r!   abspathjoin)r'   prefixsuffixnewpathuse_extr(   r)   r   r   r   fname_presuffixl   s     
r2   c             C   s,   g }x"| D ]}|j t||||| q
W |S )z*Calls fname_presuffix for a list of files.)appendr2   )fnamesr.   r/   r0   r1   f2r'   r   r   r   fnames_presuffix   s    
r6   c             C   s,   t | \}}}dj|d||f}tj||S )zZrenames a file given original filename and hash
    and sets path to output_directory
    r+   Z_0x)r*   r-   r!   )filename	hashvaluer   namer)   Znewfilenamer   r   r   hash_rename   s    r:   c             C   sH   t | tr| d } tj| \}}tjd|r@tjd|}d|fS dS dS )z)checks if file has a hash in its filenamer   z(_0x[a-z0-9]{32})TFN)FN)r   listr!   splitresearchfindall)r7   r   r9   r8   r   r   r   check_forhash   s    
r@   i    c          	   C   sb   t j| s|rtd|  dS | }t| d&}x|j|}|sBP |j| q2W W dQ R X |j S )a  
    Computes hash of a file using 'crypto' module

    >>> hash_infile('smri_ants_registration_settings.json')
    'f225785dfb0db9032aa5a0e4f2c730ad'

    >>> hash_infile('surf01.vtk')
    'fdf1cf359b4e346034372cdeb58f9a88'

    >>> hash_infile('spminfo')
    '0dc55e3888c98a182dab179b976dfffc'

    >>> hash_infile('fsl_motion_outliers_fd.txt')
    'defd1812c22405b1ee4431aac5bbdd73'


    zFile "%s" not found.Nrb)r!   isfileRuntimeErroropenreadupdate	hexdigest)afileZ	chunk_lenZcryptoZraise_notfoundZ
crypto_objfpdatar   r   r   hash_infile   s    

rK   c             C   sR   d}t j| rNt }tj| }|jt|jj  |jt|j	j  |j
 }|S )z,Computes md5 hash of the timestamp of a fileN)r!   rB   r   osstatrF   r   st_sizeencodest_mtimerG   )rH   Zmd5hexZmd5objrM   r   r   r   hash_timestamp   s    

rQ   c                s   | dkrg S t jdfdd|j j D }tdd |D dd d	d
}dd |D  x$|D ]\}}|dkr`tjd| q`W  fdd|D S )zParses the output of ``mount`` to produce (path, fs_type) pairs

    Separated from _generate_cifs_table to enable testing logic with real
    outputs
    r   z%.*? on (/.*?) (?:type |\()([^\s,\)]+)c                s   g | ]}|r| j |fqS r   )match).0l)patternr   r   
<listcomp>   s    z&_parse_mount_table.<locals>.<listcomp>c             s   s"   | ]\}}|d k	r|j  V  qd S )N)groups)rS   _rR   r   r   r   	<genexpr>   s    z%_parse_mount_table.<locals>.<genexpr>c             S   s   t | d S )Nr   )r$   )xr   r   r   <lambda>   s    z$_parse_mount_table.<locals>.<lambda>T)keyreversec             S   s    g | ]\}}|j  d kr|qS )cifs)r%   )rS   r   fstyper   r   r   rV      s    NzCannot parse mount line: '%s'c                s&   g | ] t  fd dD r qS )c             3   s   | ]} d  j |V  qdS )r   N)
startswith)rS   r   )mountr   r   rY     s    z0_parse_mount_table.<locals>.<listcomp>.<genexpr>)any)rS   )
cifs_paths)ra   r   rV     s   )r=   compilestrip
splitlinessortedfmloggerdebug)	exit_codeoutputmatchesZ
mount_infolinerR   r   )rc   rU   r   _parse_mount_table   s    

rn   c              C   s   t jd\} }t| |S )a-  Construct a reverse-length-ordered list of mount points that
    fall under a CIFS mount.

    This precomputation allows efficient checking for whether a given path
    would be on a CIFS filesystem.

    On systems without a ``mount`` command, or with no CIFS mounts, returns an
    empty list.
    ra   )spgetstatusoutputrn   )rj   rk   r   r   r   _generate_cifs_table  s    
rq   c             C   s(   x"t D ]\}}| j|r|dkS qW dS )ak  
    Checks whether a file path is on a CIFS filesystem mounted in a POSIX
    host (i.e., has the ``mount`` command).

    On Windows, Docker mounts host directories into containers through CIFS
    shares, which has support for Minshall+French symlinks, or text files that
    the CIFS driver exposes to the OS as symlinks.
    We have found that under concurrent access to the filesystem, this feature
    can result in failures to create or read recently-created symlinks,
    leading to inconsistent behavior and ``FileNotFoundError``.

    This check is written to support disabling symlinks on CIFS shares.

    r^   F)_cifs_tabler`   )r'   fspathr_   r   r   r   on_cifs  s    
rt   c          '   C   s  d}d}t j| |rx|tj|rt|\}	}
}tjd|
}d}|rrt|j dd d }|
dd d|  }
n|
d| 7 }
|	t	j
 |
 | }qW |dkrtjdd	j }|d
krt|rd}d
}tj|rtj|rtt	j|tj| k| | frld}nftj|| rd}nR|dkr*t}n|dkr:t}n
td|||}t jd||| || }||k}|rt jd|| n
t	j| | r|ry$t jd||  t	jtj| | W n tk
r   d
}Y nX d}| r8| r8t	jdkr8yt jd||  t	j| | W n tk
r2   d}Y nX d}|syt jd||  tj| | W n4 tj k
r } zt j!t"| W Y dd}~X nX |rdd | |fD }x6t#| D ]*\}}tj|rt|||||d
d qW |S )a>  Copy or link ``originalfile`` to ``newfile``.

    If ``use_hardlink`` is True, and the file can be hard-linked, then a
    link is created, instead of copying the file.

    If a hard link is not created and ``copy`` is False, then a symbolic
    link is created.

    Parameters
    ----------
    originalfile : str
        full path to original file
    newfile : str
        full path to new file
    copy : Bool
        specifies whether to copy or symlink files
        (default=False) but only for POSIX systems
    use_hardlink : Bool
        specifies whether to hard-link files, when able
        (Default=False), taking precedence over copy
    copy_related_files : Bool
        specifies whether to also operate on related files, as defined in
        ``related_filetype_sets``

    Returns
    -------
    None

    Nz_c[0-9]{4,4}$r   r   r
      z_c%04d	executionZhash_methodFT	timestampcontentzUnknown hash method found:z#File: %s already exists,%s, copy:%dz1File: %s already exists, not overwriting, copy:%dzLinking File: %s->%sposixzSymlinking File: %s->%szCopying File: %s->%sc             s   s   | ]}t |d dV  qdS )F)include_this_fileN)get_related_files)rS   fr   r   r   rY     s   zcopyfile.<locals>.<genexpr>)
hashmethoduse_hardlinkcopy_related_filesi)$rh   ri   r!   r   r*   r=   r>   intgrouprL   sepr   getr%   rt   lexistsislinkallreadlinkrealpath	posixpathsamefilerQ   rK   AttributeErrorunlinklinkr   r9   symlinkshutilcopyfileErrorwarningr   zip)Zoriginalfilenewfilecopy
create_newr}   r~   r   ZnewhashZorighashbaser'   r)   siZkeepZhashfnr   Zrelated_file_pairsZ	alt_ofileZ	alt_nfiler   r   r   r   /  s    &






 r   c             C   sj   g }t | \}}}xDtD ]<}||krx.|D ]&}|s:||kr*|jtj|||  q*W qW t|sf| g}|S )aL  Returns a list of related files, as defined in
    ``related_filetype_sets``, for a filename. (e.g., Nifti-Pair, Analyze (SPM)
    and AFNI files).

    Parameters
    ----------
    filename : str
        File name to find related filetypes of.
    include_this_file : bool
        If true, output includes the input filename.
    )r*   related_filetype_setsr3   r!   r-   r$   )r7   rz   Zrelated_filesr   r9   Z	this_typetype_setZrelated_typer   r   r   r{     s    

r{   c       	   	   C   s   t |}g }x~tt | D ]n\}}t|trF|j|t||||d qt|dkr\|| }nt||d d}t||||d}|j|| qW |S )a  Copy or symlink files in ``filelist`` to ``dest`` directory.

    Parameters
    ----------
    filelist : list
        List of files to copy.
    dest : path/files
        full path to destination. If it is a list of length greater
        than 1, then it assumes that these are the names of the new
        files.
    copy : Bool
        specifies whether to copy or symlink files
        (default=False) but only for posix systems

    Returns
    -------
    None

    )r   r   r
   r   )r0   )r   )	ensure_list	enumerater   r;   insert	copyfilesr$   r2   r   )	filelistdestr   r   outfilesZnewfilesr   r|   destfiler   r   r   r     s    

r   c             C   s@   t | ttfr| gS t | tr"| S t| r8dd | D S dS dS )z.Returns a list given either a string or a listc             S   s   g | ]}|qS r   r   )rS   rZ   r   r   r   rV     s    zensure_list.<locals>.<listcomp>N)r   r   bytesr;   r   )r7   r   r   r   r     s    
r   c             C   s   t | dkr| S | d S dS )zkReturns a list if filelist is a list of length greater than 1,
    otherwise returns the first element
    r
   r   N)r$   )r   r   r   r   simplify_list  s    r   c             C   sJ   t | }t |}tttj|oHtttj|ttttj|dg kS )zReturn true if all targets exist and are newer than all dependencies.

    An OSError will be raised if there are missing dependencies.
    r   )	r   r   mapr!   r   mingetmtimemaxr;   )targetsZdependenciesZtgtsdepsr   r   r   check_depends   s     r   c             C   s0   d}t | |}tj||ddd W dQ R X dS )zSave data to a json file

    Parameters
    ----------
    filename : str
        Filename to save data in.
    data : dict
        Dictionary to save in json file.

    wT   )	sort_keysindentN)rD   jsondump)r7   rJ   moderI   r   r   r   	save_json,  s    r   c          	   C   s$   t | d}tj|}W dQ R X |S )zLoad data from a json file

    Parameters
    ----------
    filename : str
        Filename to load data from.

    Returns
    -------
    data : dict

    rN)rD   r   load)r7   rI   rJ   r   r   r   	load_json<  s    r   c             G   s(   | j ds| j drt| S tdd S )NZpklZpklzz%Only pickled crashfiles are supported)endswithloadpkl
ValueError)infileargsr   r   r   	loadcrashO  s    r   c          !   C   s  t | } tjd|  | jdkr$tjnt}t }ttj	dd}d}x8t | |k rz| j
 r`d}P tjdj|  td qDW |rd	j| |}t||t| d
}|j }W dQ R X d}|jd}	|	dkrytj|d|	 }W n ttjfk
r   Y nX ||	d d }d}
y$t| j tj|}
W dQ R X W n tk
r~   t| j tj|ddd}
W dQ R X tjd Y nf tk
r } zH|rd|kr|d tkrtjd|d t |tjd |W Y dd}~X nX |
dkrtd|  |
S )z%Load a zipped or plain cPickled file.zLoading pkl: %sz.pklzrv   Zjob_finished_timeoutTFz'{}' missing; waiting 2sr   zAResult file {0} expected, but does not exist after ({1}) seconds.rA   N   
r   r
   zutf-8)fix_importsencodingz.Successfully loaded pkl in compatibility mode.versionziAttempted to open a results file generated by Nipype version %s, with an incompatible Nipype version (%s)zxNo metadata was found in the pkl file. Make sure you are currently using the same Nipype version from the generated pkl.zLoading %s resulted in None.)r   rh   ri   r/   gziprD   r   floatr   r   r   formatr   IOErrorr   rE   findr   loadsUnicodeDecodeErrorJSONDecodeErrorindirectoryparentpickleinfo	Exceptionr   errorr   r   )r   ZpklopenttimeoutZ	timed_outerror_messagepkl_fileZpkl_contentsZpkl_metadataidxZunpklr   r   r   r   r   V  s`    


r   c             C   s   t | dl}d|kr^|d }|jdj|j |jdj|j  |jd |jdj|j |jdj|d  W d	Q R X d	S )
zWrite out plain text crash filer   nodez	Node: {}
zWorking directory: {}

zNode inputs:
{}
r+   	tracebackN)rD   writer   fullname
output_dirinputsr-   )r7   recordrI   r   r   r   r   	crash2txt  s    
r   c             C   sp   |pt j d pd}|pt}y| j|}W n< tk
rf } z | j|dd}|jd| W Y dd}~X nX |j S )z
    Robustly reads a stream, sending a warning to a logger
    if some decoding error was raised.

    >>> read_stream(bytearray([65, 0xc7, 65, 10, 66]))  # doctest: +ELLIPSIS
    ['A...A', 'B']


    r
   zUTF-8replace)errorszError decoding string: %sN)localegetdefaultlocalerh   decoder   r   rf   )streamloggerr   default_encodingouterrr   r   r   read_stream  s    
r   c             C   s  ddl m} | L}|rFtjdti}|j|jd |jdjd tj|| |j	 }W d Q R X | j
drttjnt}| d }||d}	|	j| W d Q R X x`td	D ]P}
ytj||  P W q tk
r } ztjt| td
 W Y d d }~X qX qW |d S )Nr   )BytesIOr   zutf-8r   z.pklzz.tmpwb   r   )ior   r   dumpsr   r   rO   r   r   getvaluer   r   rD   rangerL   renamer   rh   ri   r   r   )r7   r   Z
versioningr   r|   metadatarx   Zpkl_openZtmpfiler   rX   r   r   r   r   savepkl  s(    r   =-~+c                s&   dj | dj  fdd| D fd S )Nr   r+   c                s   g | ]}t   qS r   )
rst_levels)rS   rX   )levelr   r   rV     s    z$write_rst_header.<locals>.<listcomp>z

)r-   )headerr   r   )r   r   write_rst_header  s    r   c             C   s:   g }x&t | D ]}|jdj|t| qW dj|d S )Nz{} {}r   z

)r   r3   r   r   r-   )itemsr.   r   itemr   r   r   write_rst_list  s    r   c             C   sD   g }x0t | j D ] \}}|jdj||t| qW dj|d S )Nz{}* {} : {}r   z

)rg   r   r3   r   r   r-   )r   r.   r   r\   valuer   r   r   write_rst_dict  s    r   c             C   s2   x,t jD ]"}tj|| d }tj|rdS qW dS )zIs distribution an editable install?

    Parameters
    ----------
    dist : string
        Package name

    # Borrowed from `pip`'s' API
    z	.egg-linkTF)sysr   r!   r-   rB   )dist	path_itemegg_linkr   r   r   dist_is_editable  s
    

r  c             C   s   t jd|  |r tj|  r dS tj| r6td|  ytj|  W n tk
r } zldd tj	| D }|j
t
jt
jgkr| rt jd|  n,|j
t
jkr|rt jd| t| |n|W Y dd}~X nX tj| dd	 dS )
z
    Empty an existing directory, without deleting it. Do not
    raise error if the path does not exist and noexist_ok is True.

    Parameters
    ----------
    path : directory that should be empty

    zRemoving contents of %sTzpath "%s" should be a directoryc             S   s2   g | ]*\}}}|D ]}|j d st|| qqS )z.nfs)r`   r   )rS   rootrX   filesfiler   r   r   rV     s   zemptydirs.<locals>.<listcomp>zvAn exception was raised trying to remove old %s, but the path seems empty. Is it an NFS mount?. Passing the exception.zFolder %s contents (%d items).N)exist_ok)rh   ri   r!   r   rB   r   r   rmtreerL   walkerrnoZ	ENOTEMPTYZEBUSYr   r$   makedirs)r   Z
noexist_okexZelcontr   r   r   	emptydirs  s&    

r  c             C   sB   yt j|  W n. tk
r< } z|jtjkr. dS d}~X nX dS )z
    Equivalent to ``rm -f``, returns ``False`` if the file did not
    exist.

    Parameters
    ----------

    filename : str
        file to be deleted

    FNT)rL   remover   r  ENOENT)r7   r   r   r   r   silentrm,  s    r  c             C   sx   |dkr(t jddjt j}|jdd t jdt j}|rLd|krL|jd}x&|D ]}tj| | |d}|rR|S qRW dS )a  
    Return the path to an executable which would be run if the given
    cmd was called. If no cmd would be called, return ``None``.

    Code for Python < 3.3 is based on a code snippet from
    http://orip.org/2009/08/python-checking-if-executable-exists-in.html

    NPATHEXTr+   r   PATH)r   )	rL   getenvr<   pathsepr   defpathr   r   which)cmdenvpathextr   r)   r7   r   r   r   r  A  s    


r  c             C   s   d}t jdkrd|  }ndt jkr,d|  }n
dt j S d}y0tj|tjtjd|d}|j \}}|j }W nB tk
r } z&|d	}tj	d
|  d|  W Y dd}~X nX |S )zReturn library dependencies of a dynamically linked executable

    Uses otool on darwin, ldd on linux. Currently doesn't support windows.

    Ndarwinzotool -L `which %s`linuxzldd `which %s`zPlatform %s not supportedT)stdoutstderrshellr  z failedzCould not get dependencies of z
s. Error:
)
r   platformro   PopenPIPEcommunicaterstripr   rh   r   )r9   environcommandr   procor   r  r   r   r   get_dependenciesZ  s     





(r)  c             C   s\   t jdkr| S i }xD| j D ]8\}}t|ts8|jd}t|tsL|jd}|||< qW |S )a  Windows requires that environment be dicts with str as keys and values
    This function converts any unicode entries for Windows only, returning the
    dictionary untouched in other environments.

    Parameters
    ----------
    env : dict
        environment dictionary with unicode or bytes keys and values

    Returns
    -------
    env : dict
        Windows: environment dictionary with str keys and values
        Other: untouched input ``env``
    ntzutf-8)rL   r9   r   r   r   r   )r  Zout_envr\   valr   r   r   canonicalize_envu  s    




r,  c       	      C   sF  yt j| |S  tk
r    Y nX |dkr0tj}| s<tdt j|jt j}t j| jt j}|d j	 |d j	 krt j
| \}}t j
|\}}t|t|A rtd| |f ntd|d |d f x@ttt|t|D ]}|| j	 || j	 krP qW |d7 }t jgt||  ||d  }|s<tjS t j| S )z#Return a relative version of a pathNzno path specifiedr   z,Cannot mix UNC and non-UNC paths (%s and %s)z&path is on drive %s, start on drive %sr
   )r!   relpathr   rL   curdirr   r,   r<   r   r%   Zsplituncboolr   r   r$   pardirr-   )	r   start
start_list	path_listZunc_pathrestZ	unc_startr   rel_listr   r   r   r-    s4     r-  c             c   s2   t j }t jt|  z
d V  W d t j| X d S )N)rL   getcwdchdirr   )r   cwdr   r   r   r     s
    
r   )r   r   r   )r   r   )r   r   )F)r+   r+   NT)r+   r+   NT)FFNFT)T)FF)NN)F)r   )r+   )r+   )F)NN)N)K__doc__r   r   r  
subprocessro   r   hashlibr   r   rL   os.pathr   r!   r=   r   
contextlibr   Zpathlibr   Z
simplejsonr   r   r   r+   r   r   r	   r   Zmiscr   	getLoggerrh   r   r   r    r*   r2   r6   r:   r@   rK   rQ   rn   rq   rr   rt   r   r{   r   r   r   Zfilename_to_listZlist_to_filenamer   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r)  r,  r-  contextmanagerr   r   r   r   r   <module>   s   




2
*
	!(    
 

#
L





*

&