U
    <c+                     @   s   d dl Z d dlZd dlmZ d dlZG dd deZedddZdd	 Z	d
d Z
dd ZdZdddddZdd Zdd ZdS )    N)Enumc                   @   s   e Zd ZdZdZdZdZdS )_SnapshotStateaU  
    These are the snapshotting-related states that IterDataPipes can be in.
    `NotStarted` - allows you to restore a snapshot and create an iterator with reset
    `Restored` - cannot restore again, allows you to create an iterator without resetting the DataPipe
    `Iterating` - can restore, will reset if you create a new iterator
    r         N)__name__
__module____qualname____doc__Z
NotStartedZRestored	Iterating r   r   M/tmp/pip-unpacked-wheel-gikjz4vx/torch/utils/data/datapipes/_hook_iterator.pyr      s   r   )returnc                 C   s   t | r| jS t| S dS )zn
    Simplify the display strings of objects for the purpose of rendering within DataPipe error messages.
    N)inspect
isfunctionr   repr)objr   r   r   _simplify_obj_name   s    
r   c                 C   sv   t | j}t }|j D ]\}}|| qg }t | D ]"\}} ||kr>||t	| f q>d
dd |D S )zA
    Generate a string for the input arguments of an object.
    z, c                 S   s   g | ]\}}| d | qS )=r   ).0namevaluer   r   r   
<listcomp>*   s     z/_generate_input_args_string.<locals>.<listcomp>)r   	signature	__class__set
parametersitemsadd
getmembersappendr   join)r   r   Zinput_param_names
param_name_resultr   r   r   r   _generate_input_args_string   s    r$   c                 C   s   | j j dt|  dS )N())r   r   r$   datapiper   r   r   _generate_iterdatapipe_msg-   s    r)   c                 C   s   dt |  dS )NziThis iterator has been invalidated because another iterator has been created from the same IterDataPipe: zt
This may be caused multiple references to the same IterDataPipe. We recommend using `.fork()` if that is necessary.)r)   r'   r   r   r   _gen_invalid_iterdatapipe_msg1   s    r*   z
For feedback regarding this single iterator per IterDataPipe constraint, feel free to comment on this issue: https://github.com/pytorch/data/issues/45.Fc                 C   s   |r2| j dk	r| j dkrd}tt| | t nht| dr| jdkrt| drv| |s~tdt| j dt qtd	n| j |krtt| t dS )
z
    Given an instance of a DataPipe and an iterator ID, check if the IDs match, and if not, raises an exception.
    In the case of ChildDataPipe, the ID gets compared to the one stored in `main_datapipe` as well.
    Nr   zR
Note that this exception is raised inside your IterDataPipe's a `__next__` method_is_child_datapipeT_check_valid_iterator_idznThis iterator has been invalidated, because a new iterator has been created from one of the ChildDataPipes of .z:ChildDataPipe must have method `_check_valid_iterator_id`.)	_valid_iterator_idRuntimeErrorr*   _feedback_msghasattrr+   r,   r)   Zmain_datapipe)r(   iterator_idZnext_method_existsZ	extra_msgr   r   r   _check_iterator_valid<   s    



r3   c                 C   s`   t | dr2| jdkr2t | dr(|   qZtdn(| jdkrDd| _n|  jd7  _|   | jS )zQ
    Given a DataPipe, updates its valid iterator ID and reset the DataPipe.
    r+   T$_set_main_datapipe_valid_iterator_idzFChildDataPipe must have method `_set_main_datapipe_valid_iterator_id`.Nr   r   )r1   r+   r4   r/   r.   resetr'   r   r   r   _set_datapipe_valid_iterator_idT   s    



r6   c                    s   fddG fddd d t rRtfdd}|d< nRdkrd tfd	d
}|d< t fdd}|d< dS )z
    Hook that is applied to all `__iter__` of metaclass `_DataPipeMeta`. This is done for the purpose of
    profiling and checking if an iterator is still valid.
    c                      s   t jj S N)torchautogradZprofilerZrecord_functionr   )profile_namer   r   profiler_record_fn_contextk   s    z1hook_iterator.<locals>.profiler_record_fn_contextc                       s<   e Zd ZdZdd Zdd Zdd Z fdd	Zd
d ZdS )z(hook_iterator.<locals>.IteratorDecoratorz
        Wrap the iterator and modifying its `__next__` method. This decorator is applied to
        DataPipes of which `__iter__` method is NOT a generator function. Those `__iter__`
        method commonly returns `self` but not necessarily.
        c                 S   s4   || _ || _|| _tj | _| j | jko,|| _d S r7   )iterator	source_dpr2   r8   r9   _profiler_enabledself_and_has_next_method)selfr<   r=   r2   Zhas_next_methodr   r   r   __init__t   s
    z1hook_iterator.<locals>.IteratorDecorator.__init__c                 S   s   | S r7   r   r@   r   r   r   __iter__|   s    z1hook_iterator.<locals>.IteratorDecorator.__iter__c                 S   s2   t | j| j t| j}| js.| j jd7  _|S )z
            Return next with logic related to iterator validity, profiler, and incrementation of samples yielded.
            r   )r3   r=   r2   nextr<   r?   _number_of_samples_yielded)r@   r#   r   r   r   	_get_next   s
    
z2hook_iterator.<locals>.IteratorDecorator._get_nextc              
      s6   | j r*   |  W  5 Q R  S Q R X n|  S d S r7   )r>   rF   rB   r;   r   r   __next__   s    z1hook_iterator.<locals>.IteratorDecorator.__next__c                 S   s   t | j|S r7   )getattrr<   )r@   r   r   r   r   __getattr__   s    z4hook_iterator.<locals>.IteratorDecorator.__getattr__N)	r   r   r   r	   rA   rC   rF   rH   rJ   r   rG   r   r   IteratorDecoratorn   s   
	rK   rC   c               
   ?   s   | |}| d }|j rT|j }d |_ tj|_zt|V  W q, tk
rP   Y d S X q,t|}tj	 }z|r  |
d }W 5 Q R X n
|
d }| jd7  _|V }|rԈ  t|| |
|}W 5 Q R X qt|| |
|}qW n tk
r }	 z
W Y d S d }	~	X Y n tk
r }	 z| d }d}
d}t|	jdr|
 d|jj dt| d}t|	jdkst|	jd tsd	| f|	_nF|
|	jd kr||	jd kr|	jd d	|  f|	jdd   |	_ W 5 d }	~	X Y nX d S )
Nr   r   zthrown by __iter__ ofz+single iterator per IterDataPipe constraint__len__ r%   r&   z
This exception is )_fast_forward_iteratorr   r
   _snapshot_staterD   StopIterationr6   r8   r9   r>   sendrE   r3   	Exceptionr1   argsr   r   r$   len
isinstancestr)rS   kwargsgenr(   itr2   r>   responserequestemsgZsingle_iterator_msgZfull_msg)funcr;   r   r   wrap_generator   sL    





" &z%hook_iterator.<locals>.wrap_generatorrH   c               	      sL   t j r(   | |}W 5 Q R X n
 | |}| d }| jd7  _|S )Nr   r   )r8   r9   r>   rE   )rS   rW   r#   r(   )	next_funcr;   r   r   	wrap_next   s    

z hook_iterator.<locals>.wrap_nextc                     sJ   | |}| d }t j|_|jr0|j}d |_|S t|} |||dkS )Nr   rH   )r   r
   rO   rN   r6   )rS   rW   Ziter_retr(   r2   )rK   r^   	namespacer   r   	wrap_iter   s    
z hook_iterator.<locals>.wrap_iterN)r   isgeneratorfunction	functoolswraps)rb   r:   r_   ra   rc   r   )rK   r^   rb   r`   r:   r;   r   hook_iteratorf   s    '
0

rg   )F)r   re   enumr   Ztorch.autogradr8   r   rV   r   r$   r)   r*   r0   r3   r6   rg   r   r   r   r   <module>   s   
