î
&GäRM  ã               @   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 m Z m	 Z	 m
 Z
 Gd d „  d e ƒ Z Gd d „  d e ƒ Z Gd d	 „  d	 ƒ Z Gd
 d „  d e j ƒ Z e ƒ  Z e j ƒ  Gd d „  d e ƒ Z Gd d „  d e ƒ Z e ƒ  Z d S)a8   Module yoton.events

Yoton comes with a simple event system to enable event-driven applications.

All channels are capable of running without the event system, but some
channels have limitations. See the documentation of the channels for 
more information. Note that signals only work if events are processed.

é    N)ÚPropertyÚgetErrorMsgÚPackageQueuec               @   s^   e  Z d  Z d Z d d g Z d d „  Z d d „  Z d d	 „  Z d
 d „  Z d d „  Z	 d S)ÚCallableObjectak   CallableObject(callable)
    
    A class to hold a callable. If it is a plain function, its reference
    is held (because it might be a closure). If it is a method, we keep
    the function name and a weak reference to the object. In this way,
    having for instance a signal bound to a method, the object is not
    prevented from being cleaned up.
    
    Ú_obÚ_funcc             C   s    t  | d ƒ s t d ƒ ‚ n  t  | d ƒ rT t j | j ƒ |  _ | j j |  _ nH t  | d ƒ rŠ t j | j	 ƒ |  _ | j
 j |  _ n | |  _ d  |  _ d  S)NÚ__call__z&Error: given callback is not callable.Ú__self__Úim_self)ÚhasattrÚ
ValueErrorÚweakrefÚrefr	   r   Ú__func__Ú__name__r   r
   Zim_func)ÚselfÚc© r   úG/Applications/pyzo2014a/lib/python3.4/site-packages/iep/yoton/events.pyÚ__init__-   s    	zCallableObject.__init__c             C   s!   |  j  r |  j  ƒ  d k Sd Sd S)z, Get whether the weak ref is dead. 
        NF)r   )r   r   r   r   ÚisdeadA   s    	zCallableObject.isdeadc             C   sd   |  j  r: | j  r: |  j  ƒ  | j  ƒ  k o9 |  j | j k S|  j  pI | j  s\ |  j | j k Sd Sd S)z- compare this instance with another.
        FN)r   r   )r   Úotherr   r   r   ÚcompareJ   s
    (zCallableObject.comparec             C   s   |  j  j ƒ  S)N)r   Ú__str__)r   r   r   r   r   T   s    zCallableObject.__str__c             O   s›   |  j  ƒ  r d Sy1 |  j r7 t |  j ƒ  |  j ƒ } n	 |  j } Wn t k
 rY d SYn Xy | | | Ž  SWn) t k
 r– t d ƒ t t ƒ  ƒ Yn Xd S)z] call(*args, **kwargs)
        Call the callable. Exceptions are caught and printed.
        NzException while handling event:)r   r   Úgetattrr   Ú	ExceptionÚprintr   )r   ÚargsÚkwargsÚfuncr   r   r   ÚcallW   s    		
zCallableObject.callN)
r   Ú
__module__Ú__qualname__Ú__doc__Ú	__slots__r   r   r   r   r    r   r   r   r   r   !   s   		
r   c               @   sL   e  Z d  Z d Z d d d d g Z d d „  Z d d	 „  Z d
 d „  Z d S)ÚEventzí Event(callable, *args, **kwargs)
    
    An Event instance represents something that is going to be done.
    It consists of a callable and arguments to call it with.
    
    Instances of this class populate the event queue.
    
    Ú	_callableÚ_argsÚ_kwargsÚ_timeoutc             O   s@   t  | t ƒ r | |  _ n t | ƒ |  _ | |  _ | |  _ d  S)N)Ú
isinstancer   r&   r'   r(   )r   Úcallabler   r   r   r   r   r   z   s
    	zEvent.__init__c             C   s   |  j  j |  j |  j Ž  d S)z| dispatch()
        Call the callable with the arguments and keyword-arguments specified
        at initialization.
        N)r&   r    r'   r(   )r   r   r   r   Údispatch‚   s    zEvent.dispatchc             C   s   t  j |  ƒ d S)z- This is what theTimerThread calls. 
        N)ÚappÚ
post_event)r   r   r   r   Ú_on_timeout‰   s    zEvent._on_timeoutN)r   r!   r"   r#   r$   r   r,   r/   r   r   r   r   r%   p   s
   r%   c               @   sg   e  Z d  Z d Z d d „  Z e d d „  ƒ Z d d „  Z d d	 d
 „ Z d d „  Z	 d d „  Z
 d S)ÚSignala¡   Signal()
    
    The purpose of a signal is to provide an interface to bind/unbind 
    to events and to fire them. 
    
    One can bind() or unbind() a callable to the signal. When emitted, an
    event is created for each bound handler. Therefore, the event loop
    must run for signals to work.
    
    Some signals call the handlers using additional arguments to 
    specify specific information.
    
    c             C   s   g  |  _  d  S)N)Ú	_handlers)r   r   r   r   r   Ÿ   s    zSignal.__init__c             C   s   |  j  S)z. The type (__class__) of this event. 
        )Ú	__class__)r   r   r   r   Útype¢   s    zSignal.typec             C   s[   t  | ƒ } x8 |  j D]- } | j | ƒ r t d | |  f ƒ d Sq W|  j j | ƒ d S)a   bind(func)
        
        Add an eventhandler to this event.             
        
        The callback/handler (func) must be a callable. It is called
        with one argument: the event instance, which can contain 
        additional information about the event.
        
        z*Warning: handler %s already present for %sN)r   r1   r   r   Úappend)r   r   Zcnewr   r   r   r   Úbind©   s    zSignal.bindNc             C   s�   | d k r" g  |  j  d d … <n[ t | ƒ } xL d d „  |  j  Dƒ D]4 } | j | ƒ sf | j ƒ  rE |  j  j | ƒ qE qE Wd S)zt unbind(func=None)
        
        Unsubscribe a handler, If func is None, remove all handlers.  
        
        Nc             S   s   g  |  ] } | ‘ q Sr   r   )Ú.0r   r   r   r   ú
<listcomp>Ë   s   	 z!Signal.unbind.<locals>.<listcomp>)r1   r   r   r   Úremove)r   r   Zcrefr   r   r   r   ÚunbindÁ   s    zSignal.unbindc             O   sz   g  } xL |  j  D]A } | j ƒ  r2 | j | ƒ q t | | | Ž } t j | ƒ q Wx | D] } |  j  j | ƒ q\ Wd S)a   emit(*args, **kwargs)
        
        Emit the signal, calling all bound callbacks with *args and **kwargs.
        An event is queues for each callback registered to this signal.
        Therefore it is safe to call this method from another thread.
        
        N)r1   r   r4   r%   r-   r.   r8   )r   r   r   Útoremover   Úeventr   r   r   ÚemitÑ   s    
zSignal.emitc             O   sk   g  } x= |  j  D]2 } | j ƒ  r2 | j | ƒ q | j | | Ž  q Wx | D] } |  j  j | ƒ qM Wd S)zå emit_now(*args, **kwargs)
        
        Emit the signal *now*. All handlers are called from the calling
        thread. Beware, this should only be done from the same thread
        that runs the event loop.
        
        N)r1   r   r4   r    r8   )r   r   r   r:   r   r   r   r   Úemit_nowè   s    
zSignal.emit_now)r   r!   r"   r#   r   Úpropertyr3   r5   r9   r<   r=   r   r   r   r   r0   �   s   r0   c               @   sm   e  Z d  Z d Z d d „  Z d d d „ Z d d „  Z d	 d
 „  Z d d „  Z d d „  Z	 d d „  Z
 d S)ÚTheTimerThreada   TheTimerThread is a singleton thread that is used by all timers
    and delayed events to wait for a while (in a separate thread) and then
    post an event to the event-queue. By sharing a single thread timers
    stay lightweight and there is no time spend on initializing or tearing
    down threads. The downside is that when there are a lot of timers running
    at the same time, adding a timer may become a bit inefficient because
    the registered objects must be sorted each time an object is added.
    c             C   sT   t  j j |  ƒ |  j d ƒ d |  _ g  |  _ d |  _ t  j t  j ƒ  ƒ |  _	 d  S)NTF)
Ú	threadingÚThreadr   Ú	setDaemonÚ_exitÚ_timersÚ_somethingChangedÚ	ConditionÚLockÚ
_condition)r   r   r   r   r     s    			zTheTimerThread.__init__g      ð?c          
   C   sI   d |  _  |  j j ƒ  z |  j j ƒ  Wd  |  j j ƒ  X|  j | ƒ d  S)NT)rC   rH   ÚacquireÚnotifyÚreleaseÚjoin)r   Útimeoutr   r   r   Ústop  s    	zTheTimerThread.stopc             C   s•   t  | d ƒ o t  | d ƒ s- t d ƒ ‚ n  |  j j ƒ  zF | |  j k rr |  j j | ƒ |  j ƒ  d |  _ n  |  j j ƒ  Wd |  j j	 ƒ  Xd S)zê add(timer)
        Add item to the list of objects to track. The object should
        have a _timeout attribute, representing the time.time() at which 
        it runs out, and an _on_timeout() method to call when it does. 
        r)   r/   z)Cannot add this object to theTimerThread.TN)
r   r   rH   rI   rD   r4   Ú_sortrE   rJ   rK   )r   Útimerr   r   r   Úadd  s    
zTheTimerThread.addc             C   s(   t  |  j d d d „  d d ƒ|  _ d  S)NÚkeyc             S   s   |  j  S)N)r)   )Úxr   r   r   Ú<lambda>/  s    z&TheTimerThread._sort.<locals>.<lambda>ÚreverseT)ÚsortedrD   )r   r   r   r   rO   -  s    zTheTimerThread._sortc          
   C   s^   |  j  j ƒ  z< | |  j k r2 |  j j | ƒ n  d |  _ |  j  j ƒ  Wd |  j  j ƒ  Xd S)z(Stop the timer if it hasn't finished yetTN)rH   rI   rD   r8   rE   rJ   rK   )r   rP   r   r   r   Údiscard1  s    	zTheTimerThread.discardc          
   C   s0   |  j  j ƒ  z |  j ƒ  Wd  |  j  j ƒ  Xd  S)N)rH   rI   Ú	_mainlooprK   )r   r   r   r   Úrun<  s    zTheTimerThread.runc             C   sÇ   xÀ |  j  sÂ d |  _ |  j r` |  j d } | j t j ƒ  } | d k rs |  j j | ƒ qs n d  } |  j j ƒ  |  j  r€ Pn  | d  k	 r |  j r | j ƒ  r¯ |  j ƒ  q¿ |  j j	 ƒ  q q Wd  S)NFé   r   éÿÿÿÿ)
rC   rE   rD   r)   ÚtimerH   Úwaitr/   rO   Úpop)r   rP   rM   r   r   r   rX   C  s    			zTheTimerThread._mainloopN)r   r!   r"   r#   r   rN   rQ   rO   rW   rY   rX   r   r   r   r   r?   ÿ   s   	r?   c               @   sˆ   e  Z d  Z d Z d d d d „ Z e d d „  ƒ Z e d d	 „  ƒ Z e d
 d „  ƒ Z	 d d d d „ Z
 d d „  Z d d „  Z d S)ÚTimera]   Timer(interval=1.0, oneshot=True) 
    
    Timer class. You can bind callbacks to the timer. The timer is 
    fired when it runs out of time. 
    
    Parameters
    ----------
    interval : number
        The interval of the timer in seconds.
    oneshot : bool
        Whether the timer should do a single shot, or run continuously.
    
    g      ð?Tc             C   s,   t  j |  ƒ | |  _ | |  _ d |  _ d  S)Nr   )r0   r   ÚintervalÚoneshotr)   )r   r`   ra   r   r   r   r   t  s    		zTimer.__init__c              C   s   d d „  }  d d „  } t  ƒ  S)z2 Set/get the timer's interval in seconds.
        c             S   s   |  j  S)N)Ú	_interval)r   r   r   r   Úfget‚  s    zTimer.interval.<locals>.fgetc             S   sR   t  | t t f ƒ s$ t d ƒ ‚ n  | d k r? t d ƒ ‚ n  t | ƒ |  _ d  S)Nz$interval must be a float or integer.r   zinterval must be larger than 0.)r*   ÚintÚfloatr   rb   )r   Úvaluer   r   r   Úfset„  s
    zTimer.interval.<locals>.fset)Úlocals)rc   rg   r   r   r   r`   ~  s    zTimer.intervalc              C   s   d d „  }  d d „  } t  ƒ  S)zW Set/get whether this is a oneshot timer. If not is runs
        continuously.
        c             S   s   |  j  S)N)Ú_oneshot)r   r   r   r   rc   ’  s    zTimer.oneshot.<locals>.fgetc             S   s   t  | ƒ |  _ d  S)N)Úboolri   )r   rf   r   r   r   rg   ”  s    zTimer.oneshot.<locals>.fset)rh   )rc   rg   r   r   r   ra   �  s    zTimer.oneshotc             C   s   |  j  d k S)z, Get whether the timer is running. 
        r   )r)   )r   r   r   r   Úrunning™  s    zTimer.runningNc             C   sW   | d k	 r | |  _  n  | d k	 r0 | |  _ n  t j ƒ  |  j  |  _ t j |  ƒ d S)z¥ start(interval=None, oneshot=None)
        
        Start the timer. If interval or oneshot are not given, 
        their current values are used.
        
        N)r`   ra   r\   r)   ÚtheTimerThreadrQ   )r   r`   ra   r   r   r   Ústart   s    zTimer.startc             C   s   t  j |  ƒ d |  _ d S)zH stop()
        
        Stop the timer from running. 
        
        r   N)rl   rW   r)   )r   r   r   r   rN   ²  s    z
Timer.stopc             C   s>   |  j  ƒ  |  j r  d |  _ d St j ƒ  |  j |  _ d Sd S)zY Method to call when the timer finishes. Called from 
        event-loop-thread.
        r   FTN)r<   ra   r)   r\   r`   )r   r   r   r   r/   ¼  s    
		zTimer._on_timeout)r   r!   r"   r#   r   r   r`   ra   r>   rk   rm   rN   r/   r   r   r   r   r_   e  s   

r_   c               @   s£   e  Z d  Z d Z e d d ƒ Z d Z d Z d Z d Z	 d d d „ Z
 d	 d
 „  Z d d „  Z d d „  Z d d d „ Z d d „  Z d d „  Z d d „  Z d S)ÚYotonApplicationaÑ   YotonApplication
    
    Represents the yoton application and contains functions for
    the event system. Multiple instances can be created, they will
    all operate on the same event queue and share attributes 
    (because these are on the class, not on the instance).
    
    One instance of this class is always accesible via yoton.app.
    For convenience, several of its methods are also accessible
    directly from the yoton module namespace.
    
    i'  ÚnewFNg        c             O   s^   t  | | | Ž } | d k r1 |  j | | ƒ n) | d k  rM |  j | ƒ n |  j | ƒ d S)aw   call_later(func, timeout=0.0, *args, **kwargs)
        
        Call the given function after the specified timeout.
        
        Parameters
        ----------
        func : callable
            The function to call.
        timeout : number
            The time to wait in seconds. If zero, the event is put on the event
            queue. If negative, the event will be put at the front of the event
            queue, so that it's processed asap.
        args : arguments
            The arguments to call func with.
        kwargs: keyword arguments.
            The keyword arguments to call func with.
        
        r   N)r%   Úpost_event_laterÚpost_event_asapr.   )r   r   rM   r   r   r;   r   r   r   Ú
call_laterî  s    zYotonApplication.call_laterc             C   s9   t  j j | ƒ t  j d k	 r5 d t  _ t  j ƒ  n  d S)zX post_event(events)
        
        Post an event to the event queue.
        
        N)rn   Ú_event_queueÚpushÚ_embedding_callback2Ú_embedding_callback1)r   r;   r   r   r   r.     s    	zYotonApplication.post_eventc             C   s9   t  j j | ƒ t  j d k	 r5 d t  _ t  j ƒ  n  d S)z¢ post_event_asap(event)
        
        Post an event to the event queue. Handle as soon as possible;
        putting it in front of the queue.
        
        N)rn   rs   Úinsertru   rv   )r   r;   r   r   r   rq     s    	z YotonApplication.post_event_asapc             C   s$   t  j  ƒ  | | _ t j | ƒ d S)z~ post_event_later(event, delay)
        
        Post an event to the event queue, but with a certain delay.
        
        N)r\   r)   rl   rQ   )r   r;   Zdelayr   r   r   rp   )  s    z!YotonApplication.post_event_laterc             C   sT   t  j t  _ y, x% t  j j | ƒ } | j ƒ  d } q Wn t j k
 rO Yn Xd S)a[   process_events(block=False)
        
        Process all yoton events currently in the queue. 
        This function should be called periodically
        in order to keep the yoton event system running.
        
        block can be False (no blocking), True (block), or a float 
        blocking for maximally 'block' seconds.
        
        FN)rn   rv   ru   rs   r^   r,   r   ÚEmpty)r   Úblockr;   r   r   r   Úprocess_events4  s    
zYotonApplication.process_eventsc             C   sQ   t  j r d Sd t  _ d t  _ z! x t  j s> |  j d ƒ q% WWd d t  _ Xd S)z´ start_event_loop()
        
        Enter an event loop that keeps calling yoton.process_events().
        The event loop can be stopped using stop_event_loop().
        
        NFTg      @)rn   Ú_in_event_loopÚ_stop_event_looprz   )r   r   r   r   Ústart_event_loopL  s    				z!YotonApplication.start_event_loopc             C   s8   t  j s4 d t  _ d d „  } |  j t | ƒ ƒ n  d S)z\ stop_event_loop()
        
        Stops the event loop if it is running.
        
        Tc               S   s   d  S)Nr   r   r   r   r   Údummyo  s    z/YotonApplication.stop_event_loop.<locals>.dummyN)rn   r|   r.   r%   )r   r~   r   r   r   Ústop_event_loope  s    		z YotonApplication.stop_event_loopc             C   s   | t  _ | t  _ d S)a»   embed_event_loop(callback)
        
        Embed the yoton event loop in another event loop. The given callback
        is called whenever a new yoton event is created. The callback
        should create an event in the other event-loop, which should
        lead to a call to the process_events() method. The given callback
        should be thread safe.
        
        Use None as an argument to disable the embedding. 
        
        N)rn   rv   ru   )r   Zcallbackr   r   r   Úembed_event_loops  s    	z!YotonApplication.embed_event_loop)r   r!   r"   r#   r   rs   r|   r{   rv   ru   rr   r.   rq   rp   rz   r}   r   r€   r   r   r   r   rn   Ñ  s    rn   )r#   ÚosÚsysr\   r@   r   ÚyotonÚ
yoton.miscr   r   r   Úobjectr   r%   r0   rA   r?   rl   rm   r_   rn   r-   r   r   r   r   Ú<module>   s   $O oa	
l³