U
    g,+                     @   s~   d dl mZmZmZmZmZmZ d dlmZm	Z	 d dl
mZ erLd dlmZ G dd dZG dd deZG d	d
 d
eZdS )    )TYPE_CHECKINGAnyDictOptionalTupleUnion)
RedisErrorResponseErrorstr_if_bytes)ClusterNodec                   @   s   e Zd Zdd Zdd ZdS )AbstractCommandsParserc                 G   s   t |dk rdS dd |D }|d  }d}|dkrX|d  }|dkr|dd }n,|d	krrt|dd }n|d
kr|d g}|S )z
        Get the keys from pubsub command.
        Although PubSub commands have predetermined key locations, they are not
        supported in the 'COMMAND's output, so the key positions are hardcoded
        in this method
           Nc                 S   s   g | ]}t |qS  r
   ).0argr   r   ;/tmp/pip-unpacked-wheel-f3sx1i9r/redis/_parsers/commands.py
<listcomp>   s     z;AbstractCommandsParser._get_pubsub_keys.<locals>.<listcomp>r   ZPUBSUB   )ZCHANNELSZNUMSUBZSHARDCHANNELSZSHARDNUMSUB)Z	SUBSCRIBEZ
PSUBSCRIBEZUNSUBSCRIBEZPUNSUBSCRIBE)ZPUBLISHZSPUBLISH)lenupperlist)selfargscommandkeysZpubsub_typer   r   r   _get_pubsub_keys   s    
z'AbstractCommandsParser._get_pubsub_keysc                 K   s   i }t |d }||d< t|d |d< dd |d D |d< |d	 |d
< |d |d< |d |d< t|dkr|d |d< |d |d< |d |d< |S )Nr   namer   arityc                 S   s   g | ]}t |qS r   r
   )r   flagr   r   r   r   -   s     z;AbstractCommandsParser.parse_subcommand.<locals>.<listcomp>r   flags   first_key_pos   last_key_pos   
step_count   Ztips   Zkey_specifications	   subcommands)r   intr   )r   r   optionsZcmd_dictcmd_namer   r   r   parse_subcommand(   s    z'AbstractCommandsParser.parse_subcommandN)__name__
__module____qualname__r   r.   r   r   r   r   r   
   s   r   c                   @   s0   e Zd ZdZdd Zdd Zdd Zdd	 Zd
S )CommandsParsera  
    Parses Redis commands to get command keys.
    COMMAND output is used to determine key locations.
    Commands that do not have a predefined key location are flagged with
    'movablekeys', and these commands' keys are determined by the command
    'COMMAND GETKEYS'.
    c                 C   s   i | _ | | d S N)commands
initialize)r   Zredis_connectionr   r   r   __init__A   s    zCommandsParser.__init__c                 C   sX   |  }g }|D ] }tdd |D r|| q|D ]}|||| < q6|| _d S )Nc                 s   s   | ]}|  V  qd S r3   )isupper)r   xr   r   r   	<genexpr>I   s     z,CommandsParser.initialize.<locals>.<genexpr>)r   anyappendpoplowerr4   )r   rr4   Zuppercase_commandscmdr   r   r   r5   E   s    zCommandsParser.initializec                    s  t  dk rdS  d  }|| jkr|| }|d }|| jkrV|t dd   n&| | || jkr|t|  d| j|}d|d kr| j	|f  }nd|d ks|d	 dkr| j
  }n|d
 dkrR|d dkrR|d dkrRd}d|krH| d d   }|d D ]&}	t|	d |kr | |	}d}q |sRdS |d }
|
dk rtt  t|
 }
tt|d |
d |d
 } fdd|D }|S )p  
        Get the keys from the passed command.

        NOTE: Due to a bug in redis<7.0, this function does not work properly
        for EVAL or EVALSHA when the `numkeys` arg is 0.
         - issue: https://github.com/redis/redis/issues/9493
         - fix: https://github.com/redis/redis/pull/9733

        So, don't use this function with EVAL or EVALSHA.
        r   Nr   r   ( command doesn't exist in Redis commandsmovablekeysr    pubsubr   r&   r"   r$   Fr*   |Tc                    s   g | ]} | qS r   r   r   posr   r   r   r      s     z+CommandsParser.get_keys.<locals>.<listcomp>r   r=   r4   splitr   r5   r   r   get_get_moveable_keysr   r   r.   absrange)r   
redis_connr   r-   cmd_name_splitr   r   	is_subcmdsubcmd_namesubcmdr$   keys_posr   rG   r   get_keysR   sR    









zCommandsParser.get_keysc              
   G   s|   |d   t|dd  }z|jd| }W nH tk
rv } z*| }d|ksXd|krbW Y dS |W 5 d}~X Y nX |S )aA  
        NOTE: Due to a bug in redis<7.0, this function does not work properly
        for EVAL or EVALSHA when the `numkeys` arg is 0.
         - issue: https://github.com/redis/redis/issues/9493
         - fix: https://github.com/redis/redis/pull/9733

        So, don't use this function with EVAL or EVALSHA.
        r   r   NCOMMAND GETKEYSInvalid arguments The command has no key arguments)rU   )rI   r   execute_commandr	   __str__)r   rN   r   piecesr   emessager   r   r   rK      s    
z!CommandsParser._get_moveable_keysN)r/   r0   r1   __doc__r6   r5   rT   rK   r   r   r   r   r2   8   s
   Ar2   c                   @   sp   e Zd ZdZdZddddZded ddd	d
Zeee	e
df  dddZeee	e
df  dddZdS )AsyncCommandsParsera%  
    Parses Redis commands to get command keys.

    COMMAND output is used to determine key locations.
    Commands that do not have a predefined key location are flagged with 'movablekeys',
    and these commands' keys are determined by the command 'COMMAND GETKEYS'.

    NOTE: Due to a bug in redis<7.0, this does not work properly
    for EVAL or EVALSHA when the `numkeys` arg is 0.
     - issue: https://github.com/redis/redis/issues/9493
     - fix: https://github.com/redis/redis/pull/9733

    So, don't use this with EVAL or EVALSHA.
    )r4   nodeN)returnc                 C   s
   i | _ d S r3   )r4   )r   r   r   r   r6      s    zAsyncCommandsParser.__init__r   )r_   r`   c                    s4   |r
|| _ | j dI d H }dd | D | _d S )NZCOMMANDc                 S   s   i | ]\}}|  |qS r   )r=   )r   r?   r   r   r   r   
<dictcomp>   s      z2AsyncCommandsParser.initialize.<locals>.<dictcomp>)r_   rX   itemsr4   )r   r_   r4   r   r   r   r5      s    zAsyncCommandsParser.initialize.)r   r`   c                    s  t  dk rdS  d  }|| jkr| }|d }|| jkrV|t dd   n*|  I dH  || jkrt|  d| j|}d|d kr| j	  I dH }nd|d ks|d	 dkr| j
  }n|d
 dkrV|d dkrV|d dkrVd}d|krL| d d   }|d D ]&}t|d |kr$| |}d}q$|sVdS |d }	|	dk rxt  t|	 }	tt|d |	d |d
 }
 fdd|
D }|S )r@   r   Nr   r   rA   rB   r    rC   r   r&   r"   r$   Fr*   rD   Tc                    s   g | ]} | qS r   r   rE   rG   r   r   r   	  s     z0AsyncCommandsParser.get_keys.<locals>.<listcomp>rH   )r   r   r-   rO   r   r   rP   rQ   rR   r$   rS   r   rG   r   rT      sR    








zAsyncCommandsParser.get_keysc              
      sh   z| j jd| I d H }W nH tk
rb } z*| }d|ksDd|krNW Y d S |W 5 d }~X Y nX |S )NrU   rV   rW   )rU   )r_   rX   r	   rY   )r   r   r   r[   r\   r   r   r   rK     s    
z&AsyncCommandsParser._get_moveable_keys)N)r/   r0   r1   r]   	__slots__r6   r   r5   r   r   strrT   rK   r   r   r   r   r^      s   
Ar^   N)typingr   r   r   r   r   r   Zredis.exceptionsr   r	   Zredis.utilsr   Zredis.asyncio.clusterr   r   r2   r^   r   r   r   r   <module>   s    .u