
    cC&                        d Z dZddlZddlZddlmZmZ ddlmZ ddlm	Z	m
Z
mZmZmZ ddlmZ ddlmZ  G d	 d
e      Z G d de      Z G d de      Z G d de      Z ede      Ze	 d*ddde
e   de	deegef   fd       Zed*dede
e   de	defd       Zd*dZ G d de      Zd Zd Zd Z G d d e      Z G d! d"e      Z G d# d$e      Zd% Z d& Z!d+d'e"d(e
e#   defd)Z$y),z* A few useful function/method decorators. zrestructuredtext en    N)process_timetime)isgeneratorfunction)AnyOptionalCallableoverloadTypeVar)getfullargspec)method_typec                   F    e Zd Zddee   dee   ddfdZd	dee   defdZy)
cached_decoratorN	cacheattrkeyargreturnc                      || _         || _        y N)r   r   )selfr   r   s      ;/usr/lib/python3/dist-packages/logilab/common/decorators.py__init__zcached_decorator.__init__&   s    "    callableobjc                    t        |      r
J d|z         |J t        t        |      j                        dk(  s| j                  dk(  r&t        || j                        }|j                         S | j                  r1t        || j                  | j                        }|j                         S t        || j                        }|j                         S )Nz#cannot cache generator function: %s   r   )
r   lenr   argsr   _SingleValueCacher   _MultiValuesKeyArgCache_MultiValuesCacheclosure)r   r   caches      r   __call__zcached_decorator.__call__*   s    &{3 	
1K?	
3 &&&~k*//0A59I%k4>>BE
 }}	 [[+KdnnUE }} &k4>>BE}}r   NNr   )	__name__
__module____qualname__r   strintr   r   r"    r   r   r   r   %   s=    (3-  Y] HX$6 ( r   r   c                   @    e Zd Zd	dedee   ddfdZd ZdefdZd Z	y)
r   Nr   r   r   c                 p    || _         |d|j                  z  | _        y ||j                  k7  sJ || _        y )Nz
_%s_cache_)callabler$   r   )r   r   r   s      r   r   z_SingleValueCache.__init__9   s<    #)K,@,@@DN 4 4444&DNr   c                     	 |j                   | j                     S # t        $ r/  | j                  |g| }t	        || j                  |       |cY S w xY wr   )__dict__r   KeyErrorr,   setattr)_SingleValueCache__mer   r   values       r   r"   z_SingleValueCache.__call__A   sS    	==00 	!DMM$..ED$..%0L	s    5AAc                       fd} |_         	  j                  j                  |_         j                  j                  |_        |S # t        $ r Y |S w xY w)Nc                  (     j                   | i |S r   )r"   )r   kwargsr   s     r   wrappedz*_SingleValueCache.closure.<locals>.wrappedJ   s     4==$1&11r   )	cache_objr,   __doc__r$   	Exceptionr   r6   s   ` r   r    z_SingleValueCache.closureI   sZ    	2
 !	"mm33GO#}}55G   		s   6A 	AAc                 P    |j                   j                  | j                  d        y r   )r.   popr   )r   holders     r   clearz_SingleValueCache.clearW   s    DNND1r   r   )
r$   r%   r&   r   r   r'   r   r"   r    r>   r)   r   r   r   r   8   s7    'H '# 'RV ' 2r   r   c                       e Zd Zd Zd Zy)r   c                     	 |j                   | j                     }|S # t        $ r i }t        || j                  |       Y |S w xY wr   )r.   r   r/   r0   )r   r=   _caches      r   
_get_cachez_MultiValuesCache._get_cache\   sK    	4__T^^4F   	4FFDNNF3	4s    "AAc                     | j                  |      }	 ||   S # t        $ r  | j                  |g| ||<   ||   cY S w xY wr   )rB   r/   r,   )_MultiValuesCache__mer   r   r5   rA   s        r   r"   z_MultiValuesCache.__call__d   sQ    &	 $< 	 (4==55F4L$<	 s    $??N)r$   r%   r&   rB   r"   r)   r   r   r   r   [   s     r   r   c            	       >     e Zd Zddededee   ddf fdZd Z xZ	S )	r   Nr   r   r   r   c                 <    t         t        |   ||       || _        y r   )superr   r   r   )r   r   r   r   	__class__s       r   r   z _MultiValuesKeyArgCache.__init__n   s    %t5k9Mr   c                     | j                  |      }|| j                  dz
     }	 ||   S # t        $ r!  | j                  |g|i |||<   ||   cY S w xY w)Nr   )rB   r   r/   r,   )_MultiValuesKeyArgCache__mer   r   r5   rA   keys         r   r"   z _MultiValuesKeyArgCache.__call__r   sh    &4;;?#	#; 	'$-->t>v>F3K#;	s   * 'AAr   )
r$   r%   r&   r   r(   r   r'   r   r"   __classcell__)rH   s   @r   r   r   m   s.    H c hsm _c r   r   _T)boundr   r   r5   r   c                      y r   r)   r   r   r5   s      r   cachedrQ      s     r   c                      y r   r)   rP   s      r   rQ   rQ      s    r   c                 :    ||d<   t        di |}| |S  ||       S )z0Simple decorator to cache result of method call.r   r)   )r   )r   r   r5   	decorators       r   rQ   rQ      s0    F8 *6*I%%r   c                       e Zd ZdZdZd Zej                  j                  e	j                  d         dk7  redefd       Zd
d	Zy)cachedpropertya  Provides a cached property equivalent to the stacking of
    @cached and @property, but more efficient.

    After first usage, the <property_name> becomes part of the object's
    __dict__. Doing:

      del obj.<property_name> empties the cache.

    Idea taken from the pyramid_ framework and the mercurial_ project.

    .. _pyramid: http://pypi.python.org/pypi/pyramid
    .. _mercurial: http://pypi.python.org/pypi/Mercurial
    )r6   c                 b    	 |j                    || _        y # t        $ r t        d|z        w xY w)Nz!%s must have a __name__ attribute)r$   AttributeError	TypeErrorr6   r:   s     r   r   zcachedproperty.__init__   s>    	K   	K?'IJJ	Ks    .r   zsphinx-buildr   c                 L    t        | j                  dd       }d|rd|z  z  S dz  S )Nr8   z+<wrapped by the cachedproperty decorator>%sz
%s )getattrr6   )r   docs     r   r8   zcachedproperty.__doc__   s/    $,,	48C@TWFSL``]_``r   Nc                 r    || S | j                  |      }t        || j                   j                  |       |S r   )r6   r0   r$   )r   instobjtypevals       r   __get__zcachedproperty.__get__   s5    <Kll4 dll++S1
r   r   )r$   r%   r&   r8   	__slots__r   ospathbasenamesysargvpropertyr'   rb   r)   r   r   rV   rV      sW     I 
ww$6 
	aS 	a 
	ar   rV   c                     | j                   }t        ||      }t        |t              r|j                  }|j
                  S r   )rH   r\   
isinstanceri   fgetr7   )objfuncnameclsmembers       r   get_cache_implrq      s6    
--CS(#F&(#r   c                 :    t        | |      j                  |        y)zClear a cache handled by the :func:`cached` decorator. If 'x' class has
    @cached on its method `foo`, type

    >>> clear_cache(x, 'foo')

    to purge this method's cache on the instance.
    N)rq   r>   )rm   rn   s     r   clear_cachers      s     3!'',r   c                     t        | |      j                  }	 t        | ||j                  |          y# t        $ r Y yw xY w)z/Copy cache for <funcname> from cacheobj to obj.N)rq   r   r0   r.   r/   )rm   rn   cacheobjr   s       r   
copy_cacherv      sB    sH-77IY 1 1) <= s   3 	??c                   "    e Zd ZdZd Zd Zd Zy)	wpropertyzSimple descriptor expecting to take a modifier function as first argument
    and looking for a _<function name> to retrieve the attribute.
    c                 :    || _         d|j                  z  | _        y )Nz_%s)setfuncr$   attrname)r   rz   s     r   r   zwproperty.__init__   s     0 00r   c                 (    | j                  ||       y r   )rz   )r   rm   r2   s      r   __set__zwproperty.__set__   s    S% r   c                 6    |J t        || j                        S r   )r\   r{   )r   rm   ro   s      r   rb   zwproperty.__get__   s    sDMM**r   N)r$   r%   r&   r8   r   r}   rb   r)   r   r   rx   rx      s    1!+r   rx   c                       e Zd ZdZd Zd Zy)classpropertyz>this is a simple property-like class but for class attributes.c                     || _         y r   get)r   r   s     r   r   zclassproperty.__init__   s	    r   c                 $    | j                  |      S r   r   )r   r_   ro   s      r   rb   zclassproperty.__get__   s    xx}r   N)r$   r%   r&   r8   r   rb   r)   r   r   r   r      s    Hr   r   c                   "    e Zd ZdZd Zd Zd Zy)iclassmethodzDescriptor for method which should be available as class method if called
    on the class or instance method if called on an instance.
    c                     || _         y r   )func)r   r   s     r   r   ziclassmethod.__init__   s	    	r   c                 v    |!t        | j                  ||j                        S t        | j                  ||      S r   )r   r   rH   )r   instancer`   s      r   rb   ziclassmethod.__get__   s4    tyy'73D3DEE499h88r   c                     t        d      )Nzcan't set attribute)rX   )r   r   r2   s      r   r}   ziclassmethod.__set__  s    233r   N)r$   r%   r&   r8   r   rb   r}   r)   r   r   r   r      s    9
4r   r   c                       fd}|S )Nc                      t               }t               } | i |}t        dj                  t               |z
  t               |z
  fz         |S )Nz%s clock: %.9f / time: %.9f)r   r   printr$   )r   r5   tcresfs        r   wrapztimed.<locals>.wrap  sL    FN  +qzz<>A;MtvXYz.ZZ[
r   r)   )r   r   s   ` r   timedr     s     Kr   c                       fd}|S )zDecorator taking two methods to acquire/release a lock as argument,
    returning a decorator function which will call the inner method after
    having called acquire(self) et will call release(self) afterwards.
    c                 J     dt         dt         dt         dt         f fd}|S )Nr   r   r5   r   c                 X     |        	  | g|i | |        S #  |        w xY wr   r)   )r   r   r5   acquirer   releases      r   wrapperz*locked.<locals>.decorator.<locals>.wrapper  s0    DM///s    
))r   )r   r   r   r   s   ` r   rT   zlocked.<locals>.decorator  s+    	# 	c 	S 	S 	 r   r)   )r   r   rT   s   `` r   lockedr     s     r   klass
methodnamec                       fd}|S )a}  Decorator extending class with the decorated callable. This is basically
    a syntactic sugar vs class assignment.

    >>> class A:
    ...     pass
    >>> @monkeypatch(A)
    ... def meth(self):
    ...     return 12
    ...
    >>> a = A()
    >>> a.meth()
    12
    >>> @monkeypatch(A, 'foo')
    ... def meth(self):
    ...     return 12
    ...
    >>> a.foo()
    12
    c                 z    	 xs | j                   }t        ||        | S # t        $ r t        d| z        w xY w)NzI%s has no __name__ attribute: you should provide an explicit `methodname`)r$   rX   r0   )r   namer   r   s     r   rT   zmonkeypatch.<locals>.decorator9  sU    	.D 	tT"  	 >@DE 	s   " :r)   )r   r   rT   s   `` r   monkeypatchr   $  s    *	 r   r#   r   )%r8   __docformat__rd   rg   r   r   inspectr   typingr   r   r   r	   r
   r   logilab.common.compatr   objectr   r   r   r   rM   r(   rQ   rV   rq   rs   rv   rx   r   r   r   r   typer'   r   r)   r   r   <module>r      sR  $ 1 & 	 
 # ' = = " -
v & 2  2F )  $/  T" 
6:&.smFIrdBh 
 
 8C= 3 SU  
&&V &R-+ +"F 46 4"& t  #  (  r   