U
    ]g                     @   s   d dl 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 dlmZ d dlmZmZmZmZmZmZmZmZmZ d dlmZ G dd	 d	eZdS )
    N)
ModuleType)cast)ConfigurationError)Storage)	CallableListMemcachedClientPOptionalPRTupleTypeUnion)get_dependencyc                       s.  e Zd ZdZdgZdgZd$eeeee	g e
f f dd fddZeeee eee d	f f d
ddZeeeeef  ee
dddZe	eef ejejedddZee
d
ddZeedddZeddddZd%eeeeedddZeedddZed
d d!Ze e d
d"d#Z!  Z"S )&MemcachedStoragez[
    Rate limit storage with memcached as backend.

    Depends on :pypi:`pymemcache`.
    Z	memcached
pymemcacheFN)uriwrap_exceptionsoptionsreturnc                    s  t j|}g | _|j dD ],}|s,q"|d\}}| j|t|f q"|j	rl|jsl|j
sl|j	g| _| jd j| _t|dd| _t|dd| _tttttttf  gtf |d| j| _|| _t| jstd	| j t | _d
| j_ t! j"||d d
S )an  
        :param uri: memcached location of the form
         ``memcached://host:port,host:port``,
         ``memcached:///var/tmp/path/to/sock``
        :param wrap_exceptions: Whether to wrap storage exceptions in
         :exc:`limits.errors.StorageError` before raising it.
        :param options: all remaining keyword arguments are passed
         directly to the constructor of :class:`pymemcache.client.base.PooledClient`
         or :class:`pymemcache.client.hash.HashClient` (if there are more than
         one hosts specified)
        :raise ConfigurationError: when :pypi:`pymemcache` is not available
        ,:r   libraryzpymemcache.clientcluster_libraryzpymemcache.client.hashclient_getterz7memcached prerequisite not available. please install %sN)r   )#urllibparseurlparsehostsnetlocstripsplitappendintpathportZdependenciesmodule
dependencystrpopr   r   r   r   r   r   r   r   
get_clientr   r   r   r   	threadinglocallocal_storagestoragesuper__init__)selfr   r   r   parsedlochostr%   	__class__ </tmp/pip-unpacked-wheel-kizsipjx/limits/storage/memcached.pyr0   #   s8    



zMemcachedStorage.__init__.)r   c                 C   s   | j jS N)r'   ZMemcacheErrorr1   r7   r7   r8   base_exceptionsW   s    z MemcachedStorage.base_exceptions)r&   r   kwargsr   c                 K   s,   t tt|dkr|j|f|n
|j||S )z
        returns a memcached client.

        :param module: the memcached module
        :param hosts: list of memcached hosts
           )r   r   lenZ
HashClientZPooledClient)r1   r&   r   r<   r7   r7   r8   r*   ]   s    


zMemcachedStorage.get_client)funcargsr<   r   c                 O   s6   d|kr,t |}d|jks,|js,|d |||S )Nnoreply)inspectgetfullargspecr@   varkwr)   )r1   r?   r@   r<   Zargspecr7   r7   r8   call_memcached_funcp   s
    

z$MemcachedStorage.call_memcached_funcc                 C   sp   t | jdr| jjsbtt| jdkr*| jn| jd }|sJtd| j | j	|| jf| j
| j_tt| jjS )zQ
        lazily creates a memcached client instance using a thread local
        r.   r=   r   zUnable to import )hasattrr-   r.   r   r>   r   r   r   r   r   r   r   r   )r1   r'   r7   r7   r8   r.   {   s     zMemcachedStorage.storage)keyr   c                 C   s   t | j|pdS )zB
        :param key: the key to get the counter value for
        r   )r#   r.   getr1   rG   r7   r7   r8   rH      s    zMemcachedStorage.getc                 C   s   | j | dS )z>
        :param key: the key to clear rate limits for
        N)r.   deleterI   r7   r7   r8   clear   s    zMemcachedStorage.clearr=   )rG   expiryelastic_expiryamountr   c                 C   s   | j | jj|||ddsh| j||p(|}|rd|  | jj|| | j | jj|d |t  |dd |S | j | jj|d |t  |dd |S )aD  
        increments the counter for a given rate limit key

        :param key: the key to increment
        :param expiry: amount in seconds for the key to expire in
        :param elastic_expiry: whether to keep extending the rate limit
         window every hit.
        :param amount: the number to increment by
        F)rA   /expires)ZexpirerA   )rE   r.   addincrtouchsettime)r1   rG   rL   rM   rN   valuer7   r7   r8   rQ      s4        

zMemcachedStorage.incrc                 C   s    t t| j|d pt S )z;
        :param key: the key to get the expiry for
        rO   )r#   floatr.   rH   rT   rI   r7   r7   r8   
get_expiry   s    zMemcachedStorage.get_expiryc                 C   s*   z|  | jjd W dS    Y dS X dS )zq
        Check if storage is healthy by calling the ``get`` command
        on the key ``limiter-check``
        zlimiter-checkTFN)rE   r.   rH   r:   r7   r7   r8   check   s
    zMemcachedStorage.checkc                 C   s   t d S r9   )NotImplementedErrorr:   r7   r7   r8   reset   s    zMemcachedStorage.reset)F)Fr=   )#__name__
__module____qualname____doc__ZSTORAGE_SCHEMEZDEPENDENCIESr(   boolr   r   r   r0   propertyr   	Exceptionr   r;   r   r   r#   r*   r
   r   r@   r<   rE   r.   rH   rK   rQ   rW   rX   r	   rZ   __classcell__r7   r7   r5   r8   r      sN    4  
        (r   )rB   r+   rT   urllib.parser   typesr   typingr   Zlimits.errorsr   Zlimits.storage.baser   Zlimits.typingr   r   r   r	   r
   r   r   r   r   Zlimits.utilr   r   r7   r7   r7   r8   <module>   s   ,