U
    b+dw                     @   s.   d dl mZmZ d dlmZ G dd dZdS )    )
RedisErrorResponseErrorstr_if_bytesc                   @   s@   e Zd ZdZdd Zd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)selfZredis_connection r   9/tmp/pip-unpacked-wheel-cdsyf3nb/redis/commands/parser.py__init__   s    zCommandsParser.__init__c                 C   sZ   | d}g }|D ] }tdd |D r|| q|D ]}|||| < q8|| _d S )NZCOMMANDc                 s   s   | ]}|  V  qd S r   )isupper).0xr   r   r   	<genexpr>   s     z,CommandsParser.initialize.<locals>.<genexpr>)execute_commandanyappendpoplowerr   )r
   rr   Zuppercase_commandscmdr   r   r   r	      s    
zCommandsParser.initializec                 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   name   arityc                 S   s   g | ]}t |qS r   r   )r   flagr   r   r   
<listcomp>!   s     z3CommandsParser.parse_subcommand.<locals>.<listcomp>   flags   first_key_pos   last_key_pos   
step_count   Ztips   Zkey_specifications	   subcommands)r   intlen)r
   commandoptionsZcmd_dictcmd_namer   r   r   parse_subcommand   s    zCommandsParser.parse_subcommandc                    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 )ap  
        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   z( command doesn't exist in Redis commandsZmovablekeysr   Zpubsubr   r%   r!   r#   Fr)   |Tc                    s   g | ]} | qS r   r   )r   posargsr   r   r   k   s     z+CommandsParser.get_keys.<locals>.<listcomp>)r+   r   r   splitlistr	   r   upperget_get_moveable_keys_get_pubsub_keysr   r/   absrange)r
   
redis_connr3   r.   Zcmd_name_splitr,   keysZ	is_subcmdZsubcmd_nameZsubcmdr#   Zkeys_posr   r2   r   get_keys.   sR    









zCommandsParser.get_keysc              
   G   s   g }|d }||   }|t|dd  }z|jd| }W nH tk
r } z*| }d|kshd|krrW 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 GETKEYSzInvalid argumentsz The command has no key arguments)r?   )r4   r5   r   r   __str__)r
   r<   r3   piecesr.   r=   emessager   r   r   r8   o   s    	
z!CommandsParser._get_moveable_keysc                 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
        r   Nc                 S   s   g | ]}t |qS r   r   )r   argr   r   r   r      s     z3CommandsParser._get_pubsub_keys.<locals>.<listcomp>r   ZPUBSUBr   )ZCHANNELSZNUMSUB)Z	SUBSCRIBEZ
PSUBSCRIBEZUNSUBSCRIBEZPUNSUBSCRIBEZPUBLISH)r+   r6   r5   )r
   r3   r,   r=   Zpubsub_typer   r   r   r9      s    
zCommandsParser._get_pubsub_keysN)
__name__
__module____qualname____doc__r   r	   r/   r>   r8   r9   r   r   r   r   r      s   
Ar   N)Zredis.exceptionsr   r   Zredis.utilsr   r   r   r   r   r   <module>   s   