o
    Uݢg&                     @  s  d dl m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	m
Z
 d dlmZmZmZmZmZmZmZ d dlmZ d dlZd dlmZ erNd dlZdQdd	ZdRdSddZdTddZdUddZedVdWddZedXdYd dZedXdZd#dZedXd[d%dZdVd\d(dZG d)d* d*eZ d]d/d0Z!d^d_d3d4Z"d^d`d7d8Z#dad;d<Z$dbdcd@dAZ%	BdddedFdGZ&	BdddfdIdJZ'dgdKdLZ(dhdMdNZ)dbdOdPZ*dS )i    )annotationsN)IterableSequence)IOTYPE_CHECKINGAnyAnyStrLiteralTextIOoverloadpathr   returnc                 C  s   t jt jt j| S N)osr   abspath
expandvars
expanduserr    r   _/oak/stanford/groups/akundaje/marinovg/programs/cellranger-9.0.1/lib/python/cellranger/cr_io.pyfixpath   s   r   Foldpathis_dirboolc                 C  s   t | ttB std|  d t| }tj|s"td|  t	|tj
s2td| d |rDtj|sBtd|  |S tj|sRtd|  |S )N'z3' is not a valid string type and is an invalid pathzInput file does not exist: zInput file path z does not have read permissions(Please provide a directory, not a file: z(Please provide a file, not a directory: )
isinstancestrbytessysexitr   r   r   existsaccessR_OKisdirisfile)r   r   r   r   r   r   get_input_path   s   r&   pathslist[AnyStr]c                 C  s   dd | D S )Nc                 S  s   g | ]}t |qS r   )r&   ).0r   r   r   r   
<listcomp>/   s    z#get_input_paths.<locals>.<listcomp>r   )r'   r   r   r   get_input_paths.   s   r+   c                 C  sf   t | }tj|}tj|s1t|tr|jdd}tj|s)t	
d|  t	
d|  |S )Nreplace)errorsz!Output directory does not exist: r   )r   r   r   dirnamer$   r   r   decoder!   r   r    )r   r   r.   r   r   r   get_output_path2   s   
r0   rfilenamestr | bytesmodeLiteral['r']r
   c                 C     d S r   r   r2   r4   r   r   r   open_maybe_gzip>      r8   .Literal['w']c                 C  r6   r   r   r7   r   r   r   r8   B   r9   Literal['rb']io.BufferedReaderc                 C  r6   r   r   r7   r   r   r   r8   F   r9   Literal['wb']c                 C  r6   r   r   r7   r   r   r   r8   J   r9   r   IO[Any]c                 C  s   t | tst|  } | tjrt| |d}n| tj	r&t
| |}nt| |S d}|dkr;ttj||dS |dkrIttj||dS |dkrTtj||dS |dkr_tj||dS td| )	N   i   r1   )Zbuffer_sizewrbwbz"Unsupported mode for compression: )r   r   r   encodeendswithh5_constantsZGZIP_SUFFIXgzipopenZ
LZ4_SUFFIXlz4ioTextIOWrapperBufferedReaderBufferedWriter
ValueError)r2   r4   rawbufsizer   r   r   r8   N   s"   

c                      s(   e Zd Zd	 fddZd
ddZ  ZS )CRCalledProcessErrormsgr   r   Nonec                   s   t  | || _d S r   )super__init__rQ   )selfrQ   	__class__r   r   rT   h   s   
zCRCalledProcessError.__init__c                 C  s   | j S r   )rQ   )rU   r   r   r   __str__l   s   zCRCalledProcessError.__str__)rQ   r   r   rR   )r   r   )__name__
__module____qualname__rT   rX   __classcell__r   r   rV   r   rP   g   s    rP   psubprocess.CompletedProcesscmdrR   c                 C  s:   | j du rtd| d| j dkrtd| j |f dS )zRaises an exception if the completed process failed.

    Args:
        p:   Subprocess
        cmd: Command that was run

    Raises:
        CRCalledProcessError
    NzProcess did not finish: z .r   z$Process returned error code %d: %s .)
returncoderP   )r]   r_   r   r   r   check_completed_processp   s
   


ra   Texist_okc                 C  s$   |rt j| dd dS t |  dS )zCreate a directory.

    By default succeed if it already exists.

    Useful because transient NFS server issues may induce double creation attempts.
    T)rb   N)r   makedirsmkdir)r   rb   r   r   r   rd      s   rd   fnonexistent_okc              
   C  sZ   |r&zt |  W dS  ty% } z|jtjkrn W Y d}~dS d}~ww t |  dS )zDelete a file. By default succeed if it doesn't exist.

    Useful because transient NFS server issues may induce double deletion attempts.
    N)r   removeOSErrorerrnoENOENT)re   rf   er   r   r   rg      s   rg   srcdstc                   sj   ddd d fdd}t j| rtj| ||dd	 d
S t j|r.t j|t j| }|| | d
S )zHard-links src to dst, falling back to copy if it fails.

    If `src` is a directory, it will attempt to recursively hardlink.
    rl   r   rm   c              
   S  sz   z
t j| |dd W n t jy   Y dS w zt j| |dd W dS  ty< } z|jtjkr0n W Y d}~dS d}~ww )z?Copy a file, like shutil.copy2, but catch errors from copystat.F)follow_symlinksN)shutilcopyfileSameFileErrorcopystatrh   ri   EPERMrl   rm   exr   r   r   
_safe_copy   s   z*hardlink_with_fallback.<locals>._safe_copyc              
     sf   z	t | | W dS  ty2 } z|jtjtjtjtjtjfv r& | | n W Y d}~dS d}~ww )z*Hardlink a file, fallback to copy if fail.N)	r   linkrh   ri   rs   
EOPNOTSUPPZEXDEVZEMLINKEEXISTrt   rv   r   r   _hardlink_file_with_fallback   s   z<hardlink_with_fallback.<locals>._hardlink_file_with_fallbackT)copy_functiondirs_exist_okNrl   r   rm   r   )r   r   r$   ro   copytreejoinbasename)rl   rm   r{   r   rz   r   hardlink_with_fallback   s   

r   relative_pathstr | bytes | NoneAnyStr | Nonec                 C  sP   | sdS |du rt j| }|sJ t|}t| tr!|d}t| | |S )zYMake a new hard link in a stage directory to the file f, defaulting to the basename of f.Nutf8)	r   r   r   martian	make_pathr   r   r/   r   )re   r   new_pathr   r   r   	hard_link   s   



r    out_pathin_pathsIterable[str | bytes]c              
   C  sx   t | d| +}|D ]}t |d| }t|| W d    n1 s$w   Y  q
W d    d S 1 s5w   Y  d S )Nr@   r1   )rG   ro   copyfileobj)r   r   r4   out_filein_pathin_filer   r   r   concatenate_files   s   "r   Sequence[str | bytes]c              
   C  s   t | d| o}t|dkrft |d d| }| }|| t|| W d   n1 s1w   Y  |dd D ]1}t |d| }| }||ksPJ t|| W d   n1 s`w   Y  q<W d   dS W d   dS 1 syw   Y  dS )zConcatenate files, taking the first line of the first file.

    and skipping the first line for subsequent files.
    Asserts that all header lines are equal.
    r@   r   r1   N   )rG   lenreadlinewritero   r   )r   r   r4   r   r   headerr   Zthis_headerr   r   r   concatenate_headered_files   s$   
	"r   c                 C  s:   t | d}|d W d    d S 1 sw   Y  d S )NrB   s   {})rG   r   )r2   re   r   r   r   write_empty_json   s   "r   c                 C  s0   t | d	 W d   dS 1 sw   Y  dS )zCreate an empty file.rB   N)rG   r   r   r   r   touch   s   "r   c                 C  s   | du rdS |du rg }i }|   D ]N\}}|du rd||< qt|tr1t| | ||g ||< qt|trZ||g }|}td|d tj	
| d}t|| |||< qtd| |S )ad  Hard link files into this stage directory.

    For a dict with type [String,path_or_file_or_dict], where the keys represent sample IDs
    or other levels of nesting, create a dict with the same keys where all the path_or_file
    values are hardlinked into this stage directory from their old paths.
    If path_or_file_or_dict is a directory, recursively hardlink the contents of the directory.
    When nesting the key used to access each upper level will be used as a prefix
    when constructing the final file name.

    For example,

      {
        "sample1": {
          "gene_expression": "/mydir/gex.txt",
          "antibody": "/mydir/ab.txt"
        },
        "sample2": {
          "gene_expression": "/mydir/gex.txt",
          "antibody": "/mydir/ab.txt"
        },
      }

    would become

      {
        "sample1": {
          "gene_expression": "sample1_gene_expression_gex.txt",
          "antibody": "sample1_antibody.ab.txt"
         },
         "sample2": {
           "gene_expression": "sample2_gene_expression_gex.txt",
           "antibody": "sample2_antibody_ab.txt"
         },
      }
    N_r   zJInput dictionary may not contain any elements other than dict and string: )itemsr   dictrecursive_hard_link_dictr   r   r   r   r   r   r   r/   r   rM   )Zin_filesprefixesZ	out_fileskZpath_or_dictZfinal_prefixesZold_pathr   r   r   r   r     s0   $





r   )r   r   r   r   )F)r   r   r   r   r   r   )r'   r(   r   r(   )r   r   r   r   )r1   )r2   r3   r4   r5   r   r
   ).)r2   r3   r4   r:   r   r
   )r2   r3   r4   r;   r   r<   )r2   r3   r4   r=   r   r<   )r2   r3   r4   r   r   r>   )r]   r^   r_   r   r   rR   )T)r   r3   rb   r   )re   r3   rf   r   r~   r   )re   r   r   r   r   r   )r   )r   r3   r   r   r4   r   r   rR   )r   r3   r   r   r4   r   r   rR   )r2   r3   r   rR   )r   r3   r   rR   )+
__future__r   ri   rF   rI   r   ro   r   collections.abcr   r   typingr   r   r   r   r	   r
   r   Z	lz4.frameframerH   r   Zcellranger.h5_constantsrE   
subprocessr   r&   r+   r0   r8   	ExceptionrP   ra   rd   rg   r   r   r   r   r   r   r   r   r   r   r   <module>   sP   $



	
(


