U
    <c'                  	   @   s,  U d dl Z d dlZd dlmZmZmZmZmZmZ ee	 e
e	dddZe	e	e	eee	ee
f  dddZee	 ee	 ee	 d	d
dZe	e	dddZe	e	dddZe	eee	e	f ee	e	f ee	 f dddZee	 eee	e	f ee	e	f ee	 f dddZd6e	e	ee	 dddZe	e	dddZd7ee	ee	 f ee	 ee	 e	ee	e	f e	ee	 ddd Zd!Ze	ed"< d#d$hZee	 ed%< e Zee	 ed&< d'd'd(Zee	e	f ed)< d*Ze	ed+< d#d$hZee	 ed,< e Zee	 ed-< d.d/iZee	e	f ed0< dd1d2d3Ze d4kr(e!d5 e  dS )8    N)AnyDictListSetTupleUnion)linesindentationreturnc                 C   sF   d}dd|  }t | D ](\}}|dkr0||7 }||d|7 }q|S )N 
 r   )	enumeratereplace)r   r	   outputZnew_line_with_indentiline r   F/tmp/pip-unpacked-wheel-gikjz4vx/torch/utils/data/datapipes/gen_pyi.pymaterialize_lines   s    r   dirtemplate_nameoutput_namereplacementsc              
   C   s   t j| |}t j| |}t|d}| }W 5 Q R X |D ]<\}}	}
t|d"}||t|	|
}|| W 5 Q R X q>d S )Nrw)ospathjoinopenreadr   r   write)r   r   r   r   Ztemplate_pathZoutput_pathfcontentplaceholderr   r	   r   r   r   gen_from_template   s    r&   )	dir_pathsfiles_to_excluder
   c                    sV   t  }| D ]F t }dd |D }fdd|D }| fdd|D  q
|S )z
    When given a path to a directory, returns the paths to the relevant files within it.
    This function does NOT recursive traverse to subdirectories.
    c                 S   s    h | ]}d |dd kr|qS )z.pyNr   .0fnamer   r   r   	<setcomp>%   s      z"find_file_paths.<locals>.<setcomp>c                    s   h | ]}| kr|qS r   r   r*   r(   r   r   r-   &   s      c                    s   h | ]}t j |qS r   r   r   r   r*   )dir_pathr   r   r-   '   s     )setr   listdirupdate)r'   r(   paths	all_filesZpython_filesZfilter_filesr   )r0   r(   r   find_file_paths   s    
r6   )r   r
   c                 C   s\   d| krd\}}n d| kr$d\}}nt d|  | |t| | | }}| || S )zb
    Extracts method name from decorator in the form of "@functional_datapipe({method_name})"
    (")r7   z")(')r8   z')z4Unable to find appropriate method name within line:
)RuntimeErrorfindlenr   Zstart_tokenZ	end_tokenstartendr   r   r   extract_method_name+   s    

r?   c                 C   s2   d}d}|  |t| |  | }}| || S )z`
    Extracts class name from class definition in the form of "class {CLASS_NAME}({Type}):"
    class ()r:   r;   r<   r   r   r   extract_class_name9   s    rB   )	file_pathr
   c              	   C   s~  i i t    }}}t| R}d}d\}}}d}	| D ].}
|
dd dkrV|	 }	|	s8d|
krdq8d|
krvt|
}q8|rd|
krt|
}q8|rd	|
ksd
|
krd
|
kr|| |d7 }|
dtd }|
|d }
|dkr8||
d7 }||
d8 }|dkr@|
	d}||
d| 7 }t
|||< |||< d\}}}q8|dk rTtdq8||
dd7 }q8W 5 Q R X |||fS )zp
    Given a path to file, parses the file and returns a dictionary of method names to function signatures.
    r   )r   r   r   Fz"""      z@functional_datapiper@   zdef __init__(zdef __new__(rA   N)z7open parenthesis count < 0. This shouldn't be possible.r   r   )r1   r    	readlinescountr?   rB   addr:   r;   rfindprocess_signaturer9   strip)rC   method_to_signaturemethod_to_class_nameZspecial_output_typer#   Zopen_paren_countmethod_name
class_name	signatureskipr   r=   r>   r   r   r   parse_datapipe_fileC   sF    





 rS   )
file_pathsr
   c                 C   sR   i i t    }}}| D ]0}t|\}}}|| || || q|||fS )N)r1   rS   r3   )rT   methods_and_signaturesmethods_and_class_namesZ!methods_with_special_output_typesr   rM   rN   Z$methods_needing_special_output_typesr   r   r   parse_datapipe_filesm   s    

rW   ,)r   	delimiterr
   c                 C   sp   d}d}g }| D ]P}|dkr&|d7 }n2|dkr8|d8 }n ||krX|dkrX| | d}q||7 }q| | |S )z\
    Given a line of text, split it on comma unless the comma is within a bracket '[]'.
    r   r   [rE   ])append)r   rY   Zbracket_countZ
curr_tokenrescharr   r   r   split_outside_bracketw   s    




r_   c                 C   s   t | }t|D ]\}}|d||< |dkr8d||< q|dkrjd||d  krj|| d dkrjd||< qd|kr|d	d
\}}|dd ||< qdd |D }d|} | S )z
    Given a raw function signature, clean it up by removing the self-referential datapipe argument,
    default arguments of input functions, newlines, and spaces.
    r   clsselfr   rE   *r   z
Callable ==rD   z= ...c                 S   s   g | ]}|d kr|qS )r   r   )r+   tr   r   r   
<listcomp>   s      z%process_signature.<locals>.<listcomp>z, )r_   r   rL   rsplitr   )r   tokensr   tokenheadZdefault_argr   r   r   rK      s    
(

rK   r   )rC   r(   deprecated_filesdefault_output_typemethod_to_special_output_typerootr
   c                    s    dkrt ttj  t| t r,| gn| }  fdd| D } t| ||d}t	|\}}}	|D ]}
|
|	krf|	
|
 qfg }| D ]J\}}|| }||	kr|| }n|}|d| d| d| d| d		 q|jd
d d |S )a  
    .pyi generation for functional DataPipes Process
    # 1. Find files that we want to process (exclude the ones who don't)
    # 2. Parse method name and signature
    # 3. Remove first argument after self (unless it is "*datapipes"), default args, and spaces
    r   c                    s   g | ]}t j |qS r   r/   )r+   r   rm   r   r   re      s     z*get_method_definitions.<locals>.<listcomp>r.   z# Functional form of 'z'
def rA   z) -> z: ...c                 S   s   |  dd S )Nr   rE   )split)sr   r   r   <lambda>       z(get_method_definitions.<locals>.<lambda>)key)strpathlibPath__file__parentresolve
isinstancer6   unionrW   rI   itemsr\   sort)rC   r(   rj   rk   rl   rm   rT   rU   rV   Zmethods_w_special_output_typesfn_nameZmethod_definitionsrO   	argumentsrP   output_typer   rn   r   get_method_definitions   s*    
&r   iteriterDP_file_pathz__init__.pyzutils.pyiterDP_files_to_excludeiterDP_deprecated_fileszList[IterDataPipe])Zdemuxfork$iterDP_method_to_special_output_typemapmapDP_file_pathmapDP_files_to_excludemapDP_deprecated_filesshuffleIterDataPipe#mapDP_method_to_special_output_type)r
   c                  C   s\   t tttdt} t tttdt}t	
tj }d| dfd|dfg}tt|dd|d d	S )
a  
    # Inject file into template datapipe.pyi.in
    TODO: The current implementation of this script only generates interfaces for built-in methods. To generate
          interface for user-defined DataPipes, consider changing `IterDataPipe.register_datapipe_as_function`.
    r   ZMapDataPipez${IterDataPipeMethods}   z${MapDataPipeMethods}zdatapipe.pyi.inzdatapipe.pyir   N)r   r   r   r   r   r   r   r   r   ru   rv   rw   rx   ry   r&   rt   )Ziter_method_definitionsZmap_method_definitionsr   r   r   r   r   main   s"      r   __main__z2Generating Python interface file 'datapipe.pyi'...)rX   )r   )"r   ru   typingr   r   r   r   r   r   rt   intr   r&   r6   r?   rB   rS   rW   r_   rK   r   r   __annotations__r   r1   r   r   r   r   r   r   r   __name__printr   r   r   r   <module>   sB     
"
.*2
 
 (
