3
de*                 @   s   d Z ddlZddlZddlZddlmZ ddlmZ ddlmZ dZ	dZ
dZd	ZG d
d deZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZG dd deZedd ZdS )zH Record trait change events in single and multi-threaded environments.

    N)contextmanager)datetime)trait_notifierszc{time} {direction:-{direction}{length}} {name!r} changed from {old!r} to {new!r} in {class_name!r}
z0{time} {action:>{gap}}: {handler!r} in {source}
zE{time} {direction:-{direction}{length}} EXIT: {handler!r}{exception}
	   c               @   s   e Zd ZdZf Zdd ZdS )SentinelRecordzM Sentinel record to separate groups of chained change event dispatches.

    c             C   s   dS )N
 )selfr   r   :/tmp/pip-build-7vycvbft/traits/traits/util/event_tracer.py__str__*   s    zSentinelRecord.__str__N)__name__
__module____qualname____doc__	__slots__r   r   r   r   r
   r   #   s   r   c               @   s$   e Zd ZdZdZdd	 Zd
d ZdS )ChangeMessageRecordz2 Message record for a change event dispatch.

    timeindentnameoldnew
class_namec             C   s(   || _ || _|| _|| _|| _|| _d S )N)r   r   r   r   r   r   )r	   r   r   r   r   r   r   r   r   r
   __init__5   s    zChangeMessageRecord.__init__c          	   C   s,   | j d }tj| jd| j| j| j| j|dS )N   >)r   	directionr   r   r   r   length)r   	CHANGEMSGformatr   r   r   r   r   )r	   r   r   r   r
   r   C   s    
zChangeMessageRecord.__str__N)r   r   r   r   r   r   )r   r   r   r   r   r   r   r   r   r   r
   r   .   s   r   c               @   s$   e Zd ZdZdZdd Zdd	 Zd
S )CallingMessageRecordz0 Message record for a change handler call.

    r   r   handlersourcec             C   s   || _ || _|| _|| _d S )N)r   r   r    r!   )r	   r   r   r    r!   r   r   r
   r   W   s    zCallingMessageRecord.__init__c             C   s(   | j d t }tj| jd| j| j|dS )Nr   ZCALLING)r   actionr    r!   gap)r   #SPACES_TO_ALIGN_WITH_CHANGE_MESSAGE
CALLINGMSGr   r   r    r!   )r	   r#   r   r   r
   r   a   s    zCallingMessageRecord.__str__N)r   r   r    r!   )r   r   r   r   r   r   r   r   r   r   r
   r   P   s   
r   c               @   s$   e Zd ZdZdZdd Zdd	 Zd
S )ExitMessageRecordzA Message record for returning from a change event dispatch.

    r   r   r    	exceptionc             C   s   || _ || _|| _|| _d S )N)r   r   r    r'   )r	   r   r   r    r'   r   r   r
   r   s   s    zExitMessageRecord.__init__c             C   s$   | j d }tj| jd| j| j|dS )Nr   <)r   r   r    r'   r   )r   EXITMSGr   r   r    r'   )r	   r   r   r   r
   r   }   s    
zExitMessageRecord.__str__N)r   r   r    r'   )r   r   r   r   r   r   r   r   r   r   r
   r&   l   s   
r&   c               @   s(   e Zd ZdZdd Zdd Zdd ZdS )	RecordContainerzi A simple record container.

     This class is commonly used to hold records from a single thread.

    c             C   s
   g | _ d S )N)_records)r	   r   r   r
   r      s    zRecordContainer.__init__c             C   s   | j j| dS )z- Add the record into the container.

        N)r+   append)r	   recordr   r   r
   r-      s    zRecordContainer.recordc             C   s<   t |ddd$}x| jD ]}|jt| qW W dQ R X dS )z( Save the records into a file.

        wzutf-8)encodingN)openr+   writestr)r	   filenamefhr-   r   r   r
   save_to_file   s    zRecordContainer.save_to_fileN)r   r   r   r   r   r-   r5   r   r   r   r
   r*      s   r*   c               @   s(   e Zd ZdZdd Zdd Zdd ZdS )	MultiThreadRecordContainera   A container of record containers that are used by separate threads.

    Each record container is mapped to a thread name id. When a RecordContainer
    does not exist for a specific thread a new empty RecordContainer will be
    created on request.


    c             C   s   t j | _i | _d S )N)	threadingLock_creation_lock_record_containers)r	   r   r   r
   r      s    
z#MultiThreadRecordContainer.__init__c          
   C   s:   | j * | jj|}|dkr,t }|| j|< |S Q R X dS )z Return the dedicated RecordContainer for the thread.

        If no RecordContainer is found for `thread_name` then a new
        RecordContainer is created.

        N)r9   r:   getr*   )r	   thread_name	containerr   r   r
   get_change_event_collector   s    
z5MultiThreadRecordContainer.get_change_event_collectorc             C   sP   | j @ | j}x2|j D ]&\}}tjj|dj|}|j| qW W dQ R X dS )z Save records files into the directory.

        Each RecordContainer will dump its records on a separate file named
        <thread_name>.trace.

        z	{0}.traceN)r9   r:   itemsospathjoinr   r5   )r	   Zdirectory_nameZ
containersr<   r=   r3   r   r   r
   save_to_directory   s    z,MultiThreadRecordContainer.save_to_directoryN)r   r   r   r   r   r>   rC   r   r   r   r
   r6      s   r6   c               @   s*   e Zd ZdZdd Zdd Zd	ddZdS )
ChangeEventRecordera   A single thread trait change event recorder.

    Parameters
    ----------
    container : MultiThreadRecordContainer
        A container to store the records for each trait change.

    Attributes
    ----------
    container : MultiThreadRecordContainer
        A container to store the records for each trait change.
    indent : int
        Indentation level when reporting chained events.
    c             C   s   d| _ || _d S )N   )r   r=   )r	   r=   r   r   r
   r      s    zChangeEventRecorder.__init__c       	   	   C   sh   | j }tj jd}| j}|jt||||||jjd |jt	|||jt
j|d |  j d7  _ dS )zF Record a string representation of the trait change dispatch

         )r   r   r   r   r   r   )r   r   r    r!   rE   N)r   r   utcnow	isoformatr=   r-   r   	__class__r   r   inspectgetsourcefile)	r	   objr   r   r   r    r   r   r=   r   r   r
   
pre_tracer   s$    zChangeEventRecorder.pre_tracerNc             C   sl   t j jd}|  jd8  _| j}|r2dj|}	nd}	| j}
|
jt|||j|	d |dkrh|
jt	  dS )zD Record a string representation of the trait change return

        rF   rE   z [EXCEPTION: {}] )r   r   r    r'   N)
r   rG   rH   r   r   r=   r-   r&   r   r   )r	   rL   r   r   r   r    r'   r   r   Zexception_msgr=   r   r   r
   post_tracer   s    
zChangeEventRecorder.post_tracer)N)r   r   r   r   r   rM   rO   r   r   r   r
   rD      s   rD   c               @   s:   e Zd ZdZdd Zdd Zdd Zdd	d
Zdd ZdS )MultiThreadChangeEventRecordera_   A thread aware trait change recorder.

    The class manages multiple ChangeEventRecorders which record trait change
    events for each thread in a separate file.

    Parameters
    ----------
    container : MultiThreadChangeEventRecorder
        The container of RecordContainers to keep the trait change records
        for each thread.

    Attributes
    ----------
    container : MultiThreadChangeEventRecorder
        The container of RecordContainers to keep the trait change records
        for each thread.
    tracers : dict
        Mapping from threads to ChangeEventRecorder instances.
    c             C   s   i | _ tj | _|| _d S )N)tracersr7   r8   _tracer_lockr=   )r	   r=   r   r   r
   r   .  s    
z'MultiThreadChangeEventRecorder.__init__c          	   C   s   | j  i | _W dQ R X dS )z& Close and stop all logging.

        N)rR   rQ   )r	   r   r   r
   close3  s    z$MultiThreadChangeEventRecorder.closec             C   s   | j  }|j||||| dS )zu The traits pre event tracer.

        This method should be set as the global pre event tracer for traits.

        N)_get_tracerrM   )r	   rL   r   r   r   r    tracerr   r   r
   rM   :  s    z)MultiThreadChangeEventRecorder.pre_tracerNc             C   s"   | j  }|j||||||d dS )zw The traits post event tracer.

        This method should be set as the global post event tracer for traits.

        )r'   N)rT   rO   )r	   rL   r   r   r   r    r'   rU   r   r   r
   rO   C  s    z*MultiThreadChangeEventRecorder.post_tracerc          
   C   sZ   | j J tj j}|| jkrB| j}|j|}t|}|| j|< |S | j| S W d Q R X d S )N)rR   r7   current_threadr   rQ   r=   r>   rD   )r	   threadr=   Zthread_containerrU   r   r   r
   rT   L  s    



z*MultiThreadChangeEventRecorder._get_tracer)N)	r   r   r   r   r   rS   rM   rO   rT   r   r   r   r
   rP     s   	
	rP   c           
   c   sD   t  } t| d}tj|j|jd z
| V  W dtj  |j  X dS )aH   Multi-threaded trait change event tracer.

    Example
    -------

    This will install a tracer that will record all events that occur from
    setting of some_trait on the my_model instance::

        >>> from trace_recorder import record_events
        >>> with record_events() as change_event_container:
        ...     my_model.some_trait = True
        >>> change_event_container.save_to_directory('C:\dev\trace')

    The results will be stored in one file per running thread in the
    directory 'C:\dev\trace'.  The files are named after the thread being
    traced.

    )r=   )rM   rO   N)r6   rP   r   Zset_change_event_tracersrM   rO   Zclear_change_event_tracersrS   )r=   Zrecorderr   r   r
   record_eventsY  s    

rX   )r   rJ   r@   r7   
contextlibr   r   Ztraitsr   r   r%   r)   r$   objectr   r   r   r&   r*   r6   rD   rP   rX   r   r   r   r
   <module>   s&   ",K@