o
    iMo                     @   s   d dl mZ d dlmZmZmZmZmZmZm	Z	 d dl
mZmZmZ d dlmZ er0d dlmZ G dd deZG dd	 d	eZG d
d dZeeeeef f ZG dd dZG dd deZG dd deZdS )    )Enum)TYPE_CHECKINGAny	AwaitableDictOptionalTupleUnion)IncorrectPolicyType
RedisErrorResponseErrorstr_if_bytes)ClusterNodec                   @   s,   e Zd ZdZdZdZdZdZdZdZ	dZ
d	S )
RequestPolicyZ	all_nodesZ
all_shardsZall_replicasZmulti_shardspecialdefault_keylessdefault_keyeddefault_nodeN)__name__
__module____qualname__Z	ALL_NODESZ
ALL_SHARDSZALL_REPLICASZMULTI_SHARDSPECIALDEFAULT_KEYLESSDEFAULT_KEYEDZDEFAULT_NODE r   r   N/home/app/Keep/.python/lib/python3.10/site-packages/redis/_parsers/commands.pyr      s    r   c                   @   s4   e Zd ZdZdZdZdZdZdZdZ	dZ
d	Zd
ZdS )ResponsePolicyZone_succeededZall_succeededZagg_logical_andZagg_logical_orZagg_minZagg_maxZagg_sumr   r   r   N)r   r   r   ZONE_SUCCEEDEDZALL_SUCCEEDEDZAGG_LOGICAL_ANDZAGG_LOGICAL_ORZAGG_MINZAGG_MAXZAGG_SUMr   r   r   r   r   r   r   r      s    r   c                   @   s(   e Zd ZejejfdedefddZdS )CommandPoliciesrequest_policyresponse_policyc                 C   s   || _ || _d S Nr   r    )selfr   r    r   r   r   __init__$   s   
zCommandPolicies.__init__N)r   r   r   r   r   r   r$   r   r   r   r   r   #   s    r   c                   @   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r-|d  }|dv r+|dd }|S |d	v r;t|dd }|S |d
v rD|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      g | ]}t |qS r   r   ).0argr   r   r   
<listcomp>;       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)r#   argscommandkeysZpubsub_typer   r   r   _get_pubsub_keys1   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rI|d |d< |d |d< |d |d< |S )Nr   namer,   arityc                 S   r'   r   r   )r(   flagr   r   r   r*   S   r+   z;AbstractCommandsParser.parse_subcommand.<locals>.<listcomp>r&   flags   first_key_pos   last_key_pos   
step_count   tips   Zkey_specifications	   subcommands)r   intr-   )r#   r1   optionsZcmd_dictcmd_namer   r   r   parse_subcommandN   s   z'AbstractCommandsParser.parse_subcommandN)r   r   r   r3   rF   r   r   r   r   r%   0   s    r%   c                   @   s\   e Zd ZdZdd Zdd Zdd Zdd	 Z	
ddede	e de
fddZdef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 | _ || _| | j d S r!   )commandsredis_connection
initialize)r#   rI   r   r   r   r$   g   s   zCommandsParser.__init__c                 C   sX   |  }g }|D ]}tdd |D r|| q|D ]}|||| < q|| _d S )Nc                 s   s    | ]}|  V  qd S r!   )isupper)r(   xr   r   r   	<genexpr>p   s    z,CommandsParser.initialize.<locals>.<genexpr>)r1   anyappendpoplowerrH   )r#   rrH   Zuppercase_commandscmdr   r   r   rJ   l   s   

zCommandsParser.initializec                    s  t  dk rdS  d  }|| jvr>| }|d }|| jv r+|t dd   n| | || jvr>t|  d| j|}d|d v rU| j	|g R  }|S d|d v sa|d	 dkrh| j
  }|S |d
 dkr|d dkr|d dkrd}d|v r| d d   }|d D ]}	t|	d |kr| |	}|d dkrd}q|sdS |d }
|
dk rt  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movablekeysr7   pubsubr4   r=   r9   r;   FrB   |Tc                       g | ]} | qS r   r   r(   posr0   r   r   r*      r+   z+CommandsParser.get_keys.<locals>.<listcomp>r-   rQ   rH   splitr/   rJ   r   r.   get_get_moveable_keysr3   r   rF   absrange)r#   
redis_connr0   rE   cmd_name_splitr1   r2   	is_subcmdsubcmd_namesubcmdr;   keys_posr   r\   r   get_keysy   sT   





zCommandsParser.get_keysc              
   G   sx   |d   t|dd  }z|jdg|R  }W |S  ty; } z| }d|v s.d|v r5W Y d}~dS |d}~ww )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)r^   r/   execute_commandr   __str__)r#   rc   r0   piecesr2   emessager   r   r   r`      s   
z!CommandsParser._get_moveable_keysNcommand_namesubcommand_namereturnc                 C   s   |r,| j |d D ]}t|d |kr!| |}|d dk  S q
td| d| | j |d}|dur=|d dkS td| d	a  
        Determines whether a given command or subcommand is considered "keyless".

        A keyless command does not operate on specific keys, which is determined based
        on the first key position in the command or subcommand details. If the command
        or subcommand's first key position is zero or negative, it is treated as keyless.

        Parameters:
            command_name: str
                The name of the command to check.
            subcommand_name: Optional[str], default=None
                The name of the subcommand to check, if applicable. If not provided,
                the check is performed only on the command.

        Returns:
            bool
                True if the specified command or subcommand is considered keyless,
                False otherwise.

        Raises:
            ValueError
                If the specified subcommand is not found within the command or the
                specified command does not exist in the available commands.
        rB   r   r9   zSubcommand z not found in command NzCommand z not found in commandsrH   r_   r   rF   
ValueErrorr#   rr   rs   
subcommandZparsed_subcmdZcommand_detailsr   r   r   _is_keyless_command   s   
z"CommandsParser._is_keyless_commandc                    st  i   fdd| j  D ]\}}| |}|r tj}tj}ntj}tj}|d}t|dkr:|d }|d }nd}|d } 	|ddu rS|t
||di |< n
t
||d | |< |	d	}	|	d
}
|	ro|	|| |
r|
D ]C}|d }t|tr| }| ||}|rtj}tj}ntj}tj}|dd}t
||d | |< |dd D ]}||| qqsq S )  
        Retrieve and process the command policies for all commands and subcommands.

        This method traverses through commands and subcommands, extracting policy details
        from associated data structures and constructing a dictionary of commands with their
        associated policies. It supports nested data structures and handles both main commands
        and their subcommands.

        Returns:
            PolicyRecords: A collection of commands and subcommands associated with their
            respective policies.

        Raises:
            IncorrectPolicyType: If an invalid policy type is encountered during policy extraction.
        c                       t | ttfrht|  }|ds|drd|dr=|dd }zt| | | _W n t	y<   t
d| w |drf|dd }zt| | | _W dS  t	yc   t
d| w dS dS t | trz| D ]}||| qodS t | tr|  D ]
}||| qdS dS a  
            Recursively extract policies from nested data structures.

            Args:
                data: The data structure to search (can be list, dict, str, bytes, etc.)
                command_name: The command name to associate with found policies
            r   r    :r,   zIncorrect request policy type: z Incorrect response policy type: N
isinstancestrbytesr   decode
startswithr^   r   r   rw   r
   r   r    r/   dictvaluesdatamodule_namerr   policyZpolicy_typeitemvalueZcommand_with_policiesextract_policiesr   r   r     T   



z=CommandsParser.get_command_policies.<locals>.extract_policies.r,   r   coreNr"   r?   rB   rX    rH   itemsrz   r   r   r   r   r^   r-   r_   r   r   r   r   replacer#   r1   detailsZ
is_keylessZdefault_request_policyZdefault_response_policyZ
split_namer   rr   r?   rB   Zsubcommand_detailsrf   Zsubcommand_detailr   r   r   get_command_policies   sd   2






z#CommandsParser.get_command_policiesr!   )r   r   r   __doc__r$   rJ   ri   r`   r   r   boolrz   PolicyRecordsr   r   r   r   r   rG   ^   s    C
*rG   c                   @   s   e Zd ZdZdZdddZdded ddfd	d
Zdedee	e
df  fddZdedee	e
df  fddZ	dde
dee
 defddZdee f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.
    )rH   nodert   Nc                 C   s
   i | _ d S r!   )rH   )r#   r   r   r   r$     s   
zAsyncCommandsParser.__init__r   r   c                    s6   |r|| _ | j dI d H }dd | D | _d S )NZCOMMANDc                 S   s   i | ]	\}}|  |qS r   )rQ   )r(   rS   r1   r   r   r   
<dictcomp>  s    z2AsyncCommandsParser.initialize.<locals>.<dictcomp>)r   rm   r   rH   )r#   r   rH   r   r   r   rJ     s
   zAsyncCommandsParser.initializer0   .c                    s  t  dk r	dS  d  }|| jvrA| }|d }|| jv r,|t dd   n|  I dH  || jvrAt|  d| j|}d|d v rW| j	  I dH }|S d|d v sc|d	 dkrj| j
  }|S |d
 dkr|d dkr|d dkrd}d|v r| d d   }|d D ]}t|d |kr| |}|d dkrd}q|sdS |d }	|	dk rt  t|	 }	tt|d |	d |d
 }
 fdd|
D }|S )rT   r&   Nr   r,   rU   rV   r7   rW   r4   r=   r9   r;   FrB   rX   Tc                    rY   r   r   rZ   r\   r   r   r*     r+   z0AsyncCommandsParser.get_keys.<locals>.<listcomp>r]   )r#   r0   rE   rd   r1   r2   re   rf   rg   r;   rh   r   r\   r   ri     sV   




zAsyncCommandsParser.get_keysc              
      sf   z| j jdg|R  I d H }W |S  ty2 } z| }d|v s%d|v r,W Y d }~d S |d }~ww )Nrj   rk   rl   )r   rm   r   rn   )r#   r0   r2   rp   rq   r   r   r   r`     s   
z&AsyncCommandsParser._get_moveable_keysrr   rs   c                    s   |r-| j |d D ]}t|d |kr"| |}|d dk  S qtd| d| | j |d}|dur>|d dkS td| dru   rv   rx   r   r   r   rz     s   
z'AsyncCommandsParser._is_keyless_commandc                    s  i   fdd| j  D ]\}}| |I dH }|r$tj}tj}ntj}tj}|d}t|dkr>|d }|d }nd}|d } 	|ddu rW|t
||di |< n
t
||d | |< |	d	}	|	d
}
|	rs|	|| |
r|
D ]F}|d }t|tr| }| ||I dH }|rtj}tj}ntj}tj}|dd}t
||d | |< |dd D ]}||| qqwq S )r{   c                    r|   r}   r   r   r   r   r   r   :  r   zBAsyncCommandsParser.get_command_policies.<locals>.extract_policiesNr   r,   r   r   r"   r?   rB   rX   r   r   r   r   r   r   r   (  sf   2





z(AsyncCommandsParser.get_command_policies)rt   Nr!   )r   r   r   r   	__slots__r$   r   rJ   r   r   r   ri   r`   r   rz   r   r   r   r   r   r   r   r     s     

C
*r   N)enumr   typingr   r   r   r   r   r   r	   Zredis.exceptionsr
   r   r   Zredis.utilsr   Zredis.asyncio.clusterr   r   r   r   r   r   r   r%   rG   r   r   r   r   r   <module>   s    $
.  2