
    mBNj+                     F   d dl Z d dlmZ d Zd Zd Zd Zd Zd Zd	 Z	i d
e
de
de
de
de
de
de
de
de
de
de
de
de
de
de
de
de
e
e
e
e
e
e
dZdZd Zd Zd Zd  Zd! Zd" Zd# Zd$ Zd% Zd& Zd' Zd( Zd) Zd* Zd+ Zd, Zd- Zd. Zd/ Zdd0Z d1 Z!d2 Z"d3 Z#d4 Z$d5 Z%d6 Z&d7 Z'd8 Z(d9 Z)d: Z*d; Z+d< Z,d= Z-d> Z.d? Z/d@ Z0dA Z1dB Z2dC Z3dD Z4dE Z5dF Z6dG Z7dH Z8dI Z9dJ Z:dK Z;dL Z<dM Z=dN Z>dO Z?dP Z@dQ ZAdR ZBdS ZCdT ZDdU ZEdV ZFdW ZGdX ZHdY ZIdZ ZJd[ ZKd\ ZLd] ZMd^ ZNd_ ZOd` ZPda ZQdb ZRdc ZSdd ZTde ZUdf ZVdg ZWdh ZXdi ZYdj ZZdk Z[dl Z\dm Z]dn Z^do Z_dp Z`dq Zadr Zbds Zcdt Zddu Zedv Zfdw Zgdx Zhdy Zidz Zjd{ Zkd| Zld} Zmd~ Znd Zod Zpd ZqddlrmsZsmtZtmuZumvZvmwZwmxZxmyZy y)    Nstr_if_bytesc                 |    | sy	 t        |       } t        j                  j                  |       S # t        $ r Y yw xY w)z5Converts a unix timestamp to a Python datetime objectN)int
ValueErrordatetimefromtimestampresponses    g/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/redis/_parsers/helpers.pytimestamp_to_datetimer      sC    x= **844  s   / 	;;c                     t        |       } d| z   } t        d | j                         D              } d}|D ]  }|| v st        | |         | |<    | S )zDParse the results of Redis's DEBUG OBJECT command into a Python dictztype:c              3   >   K   | ]  }|j                  d         yw:Nsplit).0kvs     r   	<genexpr>z%parse_debug_object.<locals>.<genexpr>   s     =,<bBHHSM,<s   )refcountserializedlengthlrulru_seconds_idle)r   dictr   r   )r   
int_fieldsfields      r   parse_debug_objectr      sb     H%H!H=HNN,<==H MJH!(5/2HUO  O    c                    i }t        |       } fd| j                         D ]  }|s|j                  d      r|j                  d      dk7  rh|j	                  dd      \  }}|dk(  r|j                  dd      \  }}|dk(  r(|j                  dg       j                   |              |      ||<   |j                  d	g       j                  |        |S )
z;Parse the result of Redis's INFO command into a Python dictc                 \   d| vrd| vr	 d| v rt        |       S t        |       S d| vr(| j                  d      D cg c]  }|s |       c}S i }| j                  d      D ]/  }|sd|v r!|j	                  dd      \  }} |      ||<   +d||<   1 |S # t        $ r | cY S w xY wc c}w )N,=.   T)floatr   r   r   rsplit)valuevsub_dictitemk	get_values        r   r-   zparse_info.<locals>.get_value(   s    e5 0%< <'u:% */++c*:@*:QaIaL*:@@HC($;;;sA.DAq"+A,HQK%)HTN ) O   As!   B 
B B)
B)B&%B&#r   r%   cmdstat_hostmodulemodules__raw__)r   
splitlines
startswithfindr   r'   
setdefaultappend)r   infolinekeyr(   r-   s        @r   
parse_infor<   #   s    DH%H. ##%,yy~# "ZZQ/
U.(!%S!!4JC(? OOIr299)E:JK )% 0DI 	2.55d;% &( Kr   c                     t        | dd      }|j                         D ]9  \  }}|j                  d      st        |t              s)t        |dd      ||<   ; |S )z!Parse the results of MEMORY STATST)decode_keysdecode_string_valuesdb.pairs_to_dictitemsr5   
isinstancelistr   kwargsstatsr;   r(   s        r   parse_memory_statsrI   V   sU    (4PEkkm
U>>% Zt%<&4dE#J $
 Lr   c                     t        | d      }|j                         D ]8  \  }}|j                  d      st        |t              s)t        |d      ||<   : |S )zParse MEMORY STATS for unified RESP2 output.

    Unified responses decode structural keys while preserving string-like
    values as delivered, matching the approved RESP2/RESP3 unification shape.
    Tr>   r@   rA   rF   s        r   parse_memory_stats_unifiedrL   a   sP     (5Ekkm
U>>% Zt%<&u$?E#J $ Lr   c                 L   | j                         D ci c]  \  }}t        |      | }}}|j                         D ]X  \  }}|j                  d      st        |t              s)|j                         D ci c]  \  }}t        |      | c}}||<   Z |S c c}}w c c}}w )a8  Parse the results of MEMORY STATS on RESP3 wire.

    Each entry arrives as a top-level ``dict`` instead of a flat list of
    pairs; decode the keys to ``str`` and recurse into the per-database
    ``db.*`` sub-dicts so the Python shape matches what
    :func:`parse_memory_stats` produces from RESP2 wire.
    r@   )rC   r   r5   rD   r   )r   rG   r;   r(   rH   r,   r)   s          r   parse_memory_stats_resp3rN   n   s     9A8HI8H*#u\#%8HEIkkm
U>>% Zt%<9>GA,q/1,GE#J $ L	 J Hs   B9B c                     | D cg c]/  }|j                         D ci c]  \  }}t        |      | c}}1 c}}}S c c}}w c c}}}w )zParse list-of-maps responses on RESP3 wire (e.g. ``XINFO`` family).

    Each list entry arrives as a ``dict`` with bytes keys; decode the
    keys to ``str`` so the Python shape matches what
    :func:`parse_list_of_dicts` produces from RESP2 wire.
    rC   r   )r   rG   xr;   r(   s        r   parse_list_of_dicts_resp3rR   }   sD     MUUHq	B	*#u\#%	BHUUBUs   AA A Azcan-failover-its-masterzconfig-epochzdown-after-millisecondszfailover-timeoutzinfo-refreshzlast-hello-messagezlast-ok-ping-replyzlast-ping-replyzlast-ping-sentzmaster-link-down-timezmaster-portznum-other-sentinelsz
num-slaveszo-down-timezpending-commandszparallel-syncsport)quorumzrole-reported-timezs-down-timezslave-priorityzslave-repl-offsetzvoted-leader-epoch))	is_mastermaster)is_slaveslave)is_sdowns_down)is_odowno_down)is_sentinelsentinel)is_disconnecteddisconnected)is_master_downmaster_downc                 .    t         D ]  \  }}||v | |<    y)zSet ``is_master`` / ``is_slave`` / ``is_sdown`` / ``is_odown`` /
    ``is_sentinel`` / ``is_disconnected`` / ``is_master_down`` on
    ``result`` based on membership in the ``flags`` set.
    N)_SENTINEL_DERIVED_BOOLEANS)resultflagsnameflags       r   _add_derived_sentinel_booleansri      s    
 1
du}t 1r   c                 x    t        | t              }t        |d   j                  d            }t	        ||       |S Nrf   r"   )pairs_to_dict_typedSENTINEL_STATE_TYPESsetr   ri   )r+   re   rf   s      r   parse_sentinel_statero      s7     ';<Fw%%c*+E"651Mr   c                 4    t        t        t        |             S Nro   mapr   r   optionss     r   parse_sentinel_masterrv      s    L( ;<<r   c                 
   i }| D ]-  }t        |      }	 t        |   t        | |               }|||<   / t        |d   j	                  d            }||d<   t        ||       |S # t        $ r t        | |         ||<   Y |w xY wrk   )r   rm   	Exceptionrn   r   ri   )r   ru   re   r;   str_keyr(   rf   s          r   parse_sentinel_state_resp3rz      s    Fs#	:(1,x}2MNE#F7O	  w%%c*+EF7O"651M  	:*8C=9F7O	:s   A%%BBc                 Z    i }| D ]#  }t        t        t        |            }|||d   <   % |S Nrg   rr   r   ru   re   r+   states        r   parse_sentinel_mastersr      s7    F$St%<= %uV}  Mr   c                 >    i }| D ]  }t        |      }|||d   <    |S r|   rz   r   ru   re   rV   r~   s        r   parse_sentinel_masters_resp3r      s0    F*62 %uV}  Mr   c           	      Z    | D cg c]  }t        t        t        |             c}S c c}w rq   rr   r   ru   r+   s      r   #parse_sentinel_slaves_and_sentinelsr      s'    FNOhd \4!89hOOOs    (c                 @    | D cg c]  }t        |fi | c}S c c}w rq   r   r   s      r   )parse_sentinel_slaves_and_sentinels_resp3r      s%    DLMHD&t7w7HMMMs   c              #   L   K   | j                         D ]  \  }}| |  yw)zxYield key/value pairs from a RESP3 sentinel-state map as a flat
    iterable suitable for ``parse_sentinel_state``.
    N)rC   )r~   r;   r(   s      r   _flatten_resp3_state_pairsr      s&      kkm
U	 $s   "$c                 F    t        t        t        t        |                   S rq   ro   rs   r   r   rt   s     r   +parse_sentinel_master_resp3_to_resp2_legacyr      s    L2LX2V WXXr   c           	      l    i }| D ],  }t        t        t        t        |                  }|||d   <   . |S r|   r   r   s        r   ,parse_sentinel_masters_resp3_to_resp2_legacyr      sB    F$8@A
 !&uV}	 
 Mr   c                 l    | D cg c]$  }t        t        t        t        |                  & c}S c c}w rq   r   r   s      r   9parse_sentinel_slaves_and_sentinels_resp3_to_resp2_legacyr      s;     D 	S/I$/OPQ  s   )1c                 x    t        t        t        |             }t        |d   j	                  d            |d<   |S rk   ro   rs   r   rn   r   r   ru   r~   s      r   parse_sentinel_master_unifiedr     s5     \8!<=Ew--c23E'NLr   c                     i }| D ]C  }t        t        t        |            }t        |d   j	                  d            |d<   |||d   <   E |S )Nrf   r"   rg   r   r}   s        r   parse_sentinel_masters_unifiedr     sT    F$St%<=U7^11#67g %uV}  Mr   c                     g }| D ]L  }t        t        t        |            }t        |d   j	                  d            |d<   |j                  |       N |S rk   )ro   rs   r   rn   r   r8   r   ru   outr+   r~   s        r   +parse_sentinel_slaves_and_sentinels_unifiedr     sR    
C$St%<=U7^11#67g

5  Jr   c                 <    t        | fi |}t        ||d          |S Nrf   rz   ri   r   s      r   #parse_sentinel_master_unified_resp3r     s$    &x;7;E"5%.9Lr   c                 \    i }| D ]$  }t        |      }t        ||d          |||d   <   & |S )Nrf   rg   r   r   s        r   $parse_sentinel_masters_unified_resp3r   $  s>    F*62&ueGn= %uV}  Mr   c                 p    g }| D ].  }t        |fi |}t        ||d          |j                  |       0 |S r   )rz   ri   r8   r   s        r   1parse_sentinel_slaves_and_sentinels_unified_resp3r   -  sA    
C*4;7;&ueGn=

5  Jr   c                 8    | xr | d   t        | d         fxs d S Nr   r%   r   rt   s     r   parse_sentinel_get_masterr   6  s$    7!c(1+&67?4?r   c                     | i S |s|rI| ddd   }|rt        t        |      }| ddd   }|rt        t        |      }t        t        ||            S t	        |       }t        t        ||            S )z-Create a dict given a list of key/value pairsN   r%   )rs   r   r   zipiter)r   r>   r?   keysvaluesits         r   rB   rB   :  s{    	* !}|T*D!$Q$v.FCf%&&(^CBK  r   c                     t        |       }i }t        ||      D ]  \  }}||v r	  ||   |      }|||<    |S # t        $ r Y w xY wrq   )r   r   rx   )r   	type_infor   re   r;   r(   s         r   rl   rl   M  si    	hBF"bk
U)&	#u-
 s " M   s   9	AAc                 &      t         u r S  fd}|S )a  Wrap score_cast_func to handle scientific notation in RESP2 byte strings.

    Redis returns scores as byte strings in RESP2, and large numbers may use
    scientific notation (e.g., b'1.7732526297292595e+18'). Python's int() cannot
    parse scientific notation directly.  Rather than unconditionally routing
    through float() (which would change the input type for every custom
    callable), we try the original function first and only fall back to
    converting through float() on ValueError.
    c                 b    	  |       S # t         t        f$ r  t        |             cY S w xY wrq   )r   	TypeErrorr&   )rQ   score_cast_funcs    r   
_safe_castz)_wrap_score_cast_func.<locals>._safe_casti  s6    	-"1%%I& 	-"58,,	-s     ..r&   )r   r   s   ` r   _wrap_score_cast_funcr   \  s      %- r   c           	          | r|j                  d      s| S t        |j                  dt                    }t        |       }t	        t        |t        ||                  S )zr
    If ``withscores`` is specified in the options, return the response as
    a list of (value, score) pairs
    
withscoresr   )getr   r&   r   rE   r   rs   r   ru   r   r   s       r   zset_score_pairsr   r  sO    
 7;;|4+GKK8I5,QRO	hBBOR0122r   c           	          | s| S t        |j                  dt                    }t        |       }t	        t        |t        ||                  S )zRESP2-wire ZPOPMAX/ZPOPMIN -> legacy ``list[(member, score), ...]``.

    ZPOPMAX/ZPOPMIN always include scores, so this parser intentionally
    does not depend on a ``withscores`` option.
    r   )r   r   r&   r   rE   r   rs   r   s       r   zpop_score_pairsr   ~  sD     +GKK8I5,QRO	hBBOR0122r   c                     | r|j                  d      s| S t        |j                  dt                    }| d    || d         gS zi
    If ``withscores`` is specified in the options, return the response as
    a [value, score] pair
    	withscorer   r   r%   r   r   r&   r   ru   r   s      r   zset_score_for_rankr     sE    
 7;;{3+GKK8I5,QROQK!566r   c                     | r|j                  d      s| S |j                  dt              }| D cg c]  \  }}| ||      g c}}S c c}}w )zr
    If ``withscores`` is specified in the options, return the response as
    a list of [value, score] pairs
    r   r   r   r&   r   ru   r   rg   vals        r   zset_score_pairs_resp3r     sN    
 7;;|4kk"3U;O:BC(YT3T?3'((CCCs   A	c                 x    | r|j                  d      s| S |j                  dt              }| d    || d         gS r   r   r   s      r   zset_score_for_rank_resp3r     s@    
 7;;{3kk"3U;OQK!566r   c                     t        | t              r| S t        | t              r| j                         S t        | t              r| rdS dS t        t        |       d      j                         S )a  Re-encode a score back to the bytes form Redis returns on the RESP2
    wire so that custom ``score_cast_func`` callables observe the same
    input type they would receive on a RESP2 connection when the wire
    protocol is RESP3 but legacy response shapes are requested.
       1   0z.17g)rD   bytesstrencodeboolformatr&   )r(   s    r   _score_to_resp2_bytesr     sZ     %%||~%t&$&%,'..00r   c           
          | r|j                  d      s| S t        |j                  dt                    }| D cg c]  \  }}| |t        |            f c}}S c c}}w )a  Convert RESP3 nested ``[[member, score], ...]`` to today's RESP2
    ``list[(member, score)]`` shape: tuples instead of lists, scores
    re-encoded to bytes before being passed to ``score_cast_func`` so the
    cast receives the same input as on a RESP2 connection.
    r   r   r   r   r&   r   r   ru   r   memberscores        r   &zset_score_pairs_resp3_to_resp2_legacyr     sh     7;;|4+GKK8I5,QRO &%MFE 
!6u!=>?%  s   Ac                     | r|j                  d      s| S g }| D ]0  \  }}|j                  |       |j                  t        |             2 |S )a  Convert RESP3 nested ``[[member, score], ...]`` to the flat raw RESP2
    wire shape ``[member, score_bytes, ...]`` used by ZDIFF in v8.0.0b1.

    ZDIFF historically did not propagate ``withscores`` to the response
    callback, so the legacy RESP2 callback was a no-op and the raw flat
    wire response was returned to the user. This helper reproduces that
    shape on RESP3 wires so ``legacy_responses=True`` keeps emitting the
    same Python value regardless of the underlying protocol.
    r   )r   r8   r   )r   ru   flatr   r   s        r   +zset_score_pairs_resp3_to_resp2_legacy_flatr     sO     7;;|4D!F)%01 " Kr   c                     | r|j                  d      s| S t        |j                  dt                    }| d    |t        | d               gS )u9  RESP3-wire ZRANK/ZREVRANK WITHSCORE → legacy RESP2 ``[rank, score]``.

    The shape ``[rank, score]`` is identical between RESP2 and RESP3; only
    the score is re-encoded to bytes before being passed to
    ``score_cast_func`` so the cast observes the same input type it would
    on a RESP2 connection.
    r   r   r   r%   r   r   s      r   )zset_score_for_rank_resp3_to_resp2_legacyr     sK     7;;{3+GKK8I5,QROQK)>x{)KLMMr   c           
          | r|j                  d      s| S t        |j                  dt                    }t        |       }t	        ||      D cg c]  \  }}| |t        |            g c}}S c c}}w )u   RESP2-wire WITHSCORES → unified ``list[[member, score], ...]``.

    Normalises RESP2 byte-string scores through ``float`` before applying
    ``score_cast_func`` so the cast receives the same input type as on a
    RESP3 connection.
    r   r   )r   r   r&   r   r   r   ru   r   r   r   r   s         r   zset_score_pairs_unifiedr     sf     7;;|4+GKK8I5,QRO	hBCFr2;O;ZS%S/%,/0;OOOs   A0c                     | r|j                  d      s| S t        |j                  dt                    }| d    |t        | d               gS )u   RESP2-wire ZRANK/ZREVRANK WITHSCORE → unified ``[rank, score]``.

    Normalises the RESP2 byte-string score through ``float`` before
    applying ``score_cast_func`` so the cast receives the same input type
    as on a RESP3 connection.
    r   r   r   r%   r   r   s      r   zset_score_for_rank_unifiedr     sJ     7;;{3+GKK8I5,QROQKx{);<==r   c           
          | s| S t        |j                  dt                    }t        |       }t	        ||      D cg c]  \  }}| |t        |            g c}}S c c}}w )u  RESP2-wire ZPOPMAX/ZPOPMIN → unified ``list[[member, score], ...]``.

    ZPOPMAX/ZPOPMIN always include scores; no ``withscores`` gate is
    required. Scores are normalised through ``float`` before applying
    ``score_cast_func`` for parity with RESP3.
    r   )r   r   r&   r   r   r   s         r   zpop_score_pairs_unifiedr     s[     +GKK8I5,QRO	hBCFr2;O;ZS%S/%,/0;OOOs   Ac                     | s| S |j                  dt              }t        | d   t              r| D cg c]  \  }}| ||      g c}}S | d    || d         ggS c c}}w )u!  RESP3-wire ZPOPMAX/ZPOPMIN → unified ``list[[member, score], ...]``.

    Without ``count`` RESP3 returns a flat ``[member, score]``; with
    ``count`` it returns a nested ``[[member, score], ...]``. Both shapes
    are normalised to a nested list with ``score_cast_func`` applied.
    r   r   r%   )r   r&   rD   rE   r   s        r   zpop_score_pairs_resp3_unifiedr     so     kk"3U;O(1+t$>FGhss+,hGGa[/(1+6788 Hs   Ac           
          | s| S t        |j                  dt                    }t        | d   t              r&| D cg c]  \  }}| |t        |            f c}}S | d    |t        | d               fgS c c}}w )uY  RESP3-wire ZPOPMAX/ZPOPMIN → legacy RESP2 ``list[(member, score), ...]``.

    Both RESP3 shapes (flat without ``count``; nested with ``count``) are
    converted to a list of tuples. Scores are re-encoded to bytes before
    being passed to ``score_cast_func`` so the cast observes the same
    input type it would on a RESP2 connection.
    r   r   r%   )r   r   r&   rD   rE   r   r   s        r   &zpop_score_pairs_resp3_to_resp2_legacyr   #  s     +GKK8I5,QRO(1+t$ "*
!) _%:5%ABC!)
 	
 a[/*?*LMNOO	
s   A7c                 6    | sy| d   | d   t        | d         gS )u   BZPOPMAX/BZPOPMIN → unified ``[key, member, score]``.

    Works for both RESP2 (bytes score) and RESP3 (float score) wire shapes.
    Nr   r%   r   r   rt   s     r   bzpop_score_unifiedr   6  (    
 QK!eHQK&899r   c                 6    | sy| d   | d   t        | d         fS )u   RESP3-wire BZPOPMAX/BZPOPMIN → legacy RESP2 ``(key, member, score)``.

    Matches the v8.0.0b1 RESP2-wire callback shape (tuple, ``float`` score).
    Nr   r%   r   r   rt   s     r   !bzpop_score_resp3_to_resp2_legacyr   @  r   r   c           	      f    | s| S | d   | d   D cg c]  \  }}|t        |      g c}}gS c c}}w )u   RESP3-wire ZMPOP/BZMPOP → legacy RESP2 ``[name, [[member, b"score"], ...]]``.

    Re-encodes RESP3 native float scores back to the bytes form Redis
    returns on the RESP2 wire so callers observe today's RESP2 raw shape.
    r   r%   )r   r   ru   r   r   s       r   zmpop_resp3_to_resp2_legacyr   J  sE     EMa[Q[MFE&'.	/[Q Q   -c           	      f    | s| S | d   | d   D cg c]  \  }}|t        |      g c}}gS c c}}w )u   ZMPOP/BZMPOP → unified ``[name, [[member, float_score], ...]]``.

    Used for the ``legacy_responses=False`` overlay on RESP2 wire to mirror
    RESP3's native float-score shape.
    r   r%   r   r   s       r   zmpop_unifiedr   X  sC     5=a[A[MFE&%,	[A Ar   c                     | r|j                  d      s| S t        | d   t              r| S t        |       }t	        ||      D cg c]	  \  }}||g c}}S c c}}w )u)  RESP2-wire HRANDFIELD WITHVALUES → unified ``list[[field, value], ...]``.

    Plain (no-values) responses — flat list of fields — pass through.
    The ``withvalues`` option (forwarded by the command method) selects the
    pairing branch so the no-values flat result is never misread.
    
withvaluesr   )r   rD   rE   r   r   )r   ru   r   r   r(   s        r   hrandfield_unifiedr   f  sY     7;;|4(1+t$	hB/22r{;{|ueUEN{;;;s   Ac                     | r|j                  d      s| S t        | d   t              s| S g }| D ]'  \  }}|j                  |       |j                  |       ) |S )u   RESP3-wire HRANDFIELD WITHVALUES → legacy RESP2 flat ``[field, value, ...]``.

    Plain (no-values) responses — flat list of fields — pass through.
    r   r   )r   rD   rE   r8   )r   ru   r   r   r(   s        r    hrandfield_resp3_to_resp2_legacyr   u  s\    
 7;;|4hqk4(D uEE ! Kr   c                 h    | D cg c]"  }|t        |d         t        |d         gnd$ c}S c c}w )u   GEOPOS → unified ``list[list[float, float] | None]``.

    Used for the ``legacy_responses=False`` overlay on RESP2 wire to mirror
    RESP3's native ``list[list]`` shape.
    Nr   r%   r   r   ru   lls      r   parse_geopos_unifiedr     s<     PXXxBNU2a5\5A<(DxXXX   '/c                 h    | D cg c]"  }|t        |d         t        |d         fnd$ c}S c c}w )u   RESP3-wire GEOPOS → legacy RESP2 ``list[tuple(float, float) | None]``.

    Matches today's RESP2-wire callback shape (tuple coordinates).
    Nr   r%   r   r   s      r   "parse_geopos_resp3_to_resp2_legacyr    s<    
 PXXxBNU2a5\5A<(DxXXXr   c                     t        | t              r4t        |       }t        ||      D ci c]  \  }}t	        |      | c}}S t        | t
              r-| j                         D ci c]  \  }}t	        |      | c}}S | S c c}}w c c}}w )u   LCS with IDX → unified ``dict``.

    Used for the ``legacy_responses=False`` overlay on RESP2 wire to mirror
    RESP3's native ``dict`` shape. Non-IDX responses (``bytes`` / ``int``)
    pass through unchanged.
    )rD   rE   r   r   r   r   rC   )r   ru   r   r;   r(   s        r   parse_lcs_idx_unifiedr    s     (D!(^;>r2;G;ZS%S!5(;GG(D!;C>>;KL;KZS%S!5(;KLLO HLs   B(B
c                     t        | t              s| S g }| j                         D ]'  \  }}|j                  |       |j                  |       ) |S )u   RESP3-wire LCS with IDX → legacy RESP2 flat list shape.

    Reproduces today's RESP2 raw output (``[b"matches", [...], b"len", n]``).
    Non-IDX responses pass through unchanged.
    )rD   r   rC   r8   r   ru   r   r;   r(   s        r   #parse_lcs_idx_resp3_to_resp2_legacyr    sK     h%Cnn&
U

3

5 ' Jr   c                    t        | t              r-| j                         D ci c]  \  }}t        |      | }}}n4t	        | ddd   | ddd         D ci c]  \  }}t        |      | }}}d|v r|d   D cg c]  }t        |       c}|d<   d|v r|d   D cg c]  }t        |       c}|d<   |S c c}}w c c}}w c c}w c c}w )u   CLIENT TRACKINGINFO → unified ``dict[str, Any]``.

    Accepts either RESP2's flat ``[label, value, ...]`` list or RESP3's
    native ``dict`` and returns a ``dict`` with ``str`` keys.
    Nr   r%   rf   prefixes)rD   r   rC   r   r   )r   ru   r;   r(   datarh   prefixs          r   !parse_client_trackinginfo_unifiedr    s     (D!;C>>;KL;KZS%S!5(;KL "(3Q3-!$Q$@
@
U u$@ 	 
 $8<WFd+FWT?CJ?OP?OVL0?OPZK M

 GPs   B:C =C Cc                     t        | t              st        t        t        |             S g }| j                         D ]0  \  }}|j                  t	        |             |j                  |       2 |S )u   RESP3-wire CLIENT TRACKINGINFO → legacy RESP2 flat ``list``.

    Mirrors today's RESP2-wire callback (``list(map(str_if_bytes, r))``):
    labels are decoded to ``str`` while values are preserved as-is.
    )rD   r   rE   rs   r   rC   r8   r  s        r   /parse_client_trackinginfo_resp3_to_resp2_legacyr    s^     h%Ch/00Cnn&
U

<$%

5 ' Jr   c                     | r|j                  d      s| S |d   }t        t        t        |      D cg c]
  }| |d|    c}       S c c}w )z
    If ``groups`` is specified, return the response as a list of
    n-element tuples with n being the value found in options['groups']
    groupsN)r   rE   r   range)r   ru   nis       r   sort_return_tuplesr    sQ    
 7;;x0AeAh7hhqt!tnh78997s   A	c                     | y g }| D ]e  }|Pd|v r)|j                  |d   t        |d         g|dd         2|j                  |d   t        |d         f       U|j                  d       g |S )Nclaim_min_idle_timer   r%   r   )NN)r8   rB   )r   ru   r	  rs       r   parse_stream_listr    s    D=$/QqT=1#6?12?@QqT=1#678KK%  Kr   c                     t        | d      S NTrK   )rB   r
   s    r   pairs_to_dict_with_str_keysr    s    t44r   c                 4    t        t        t        |             S rq   )rE   rs   r  r
   s    r   parse_list_of_dictsr    s    /:;;r   c                 @    |j                  dd      r| S t        |       S )Nparse_justidFr   r  rt   s     r   parse_xclaimr     s     {{>5)X&&r   c                 V    |j                  dd      r| d   S t        | d         | d<   | S )Nr  Fr%   r  rt   s     r   parse_xautoclaimr"    s1    {{>5){#HQK0HQKOr   c                     t        | t              rt        | d      S | j                         D ci c]  \  }}t	        |      | c}}S c c}}w r  )rD   rE   rB   rC   r   )r   ru   r,   r)   s       r   parse_arinfor$    sG    (D!X488+3>>+;<+;41aLOQ+;<<<s   Ac                    t        | t              rt        | d      }n,| j                         D ci c]  \  }}t	        |      | }}}|j                  dd      sR|j                  d      }||d   |d   t        |d         f|d<   |d   }||d   |d   t        |d         f|d<   |S |d	   D ci c]  \  }}|t        |       c}}|d	<   t        |d
         dkD  rst        |d
   d   t              r]|d
   D 	cg c]  }	t        |	d       c}	|d
<   |d
   D ]2  }
|
d   s	|
d   d   |
d   D cg c]  }t        |d       c}|
d<   4 |S |d
   D 	cg c]/  }	|	j                         D ci c]  \  }}t	        |      | c}}1 c}}}	|d
<   |S c c}}w c c}}w c c}	w c c}w c c}}w c c}}}	w )NTrK   fullFzfirst-entryr   r%   z
last-entryentriesr  	consumers)rD   rE   rB   rC   r   r   len)r   ru   r	  r,   r)   firstlast_identrygroupgcs               r   parse_xinfo_streamr1    s   (D!X48/7~~/?@/?tq!Q"/?@;;vu%'q!5#(8]58-D"EDL!Q 3"&q'=a+A!BD" K HLIWe3e 44WYtH~"z$x.2CT'JDHNDR5e6NDN (^[>anQ&7&CDEkN&DRqaT:N&AkN $ K "(^+E 16>1a!#>+DN K1 A X
&
 ?s/   F7F%F+:F0!F;9F5F;5F;c           	      X    | g S | D cg c]  }|d   t        |d   fi |g c}S c c}w r   )r  )r   ru   r  s      r   parse_xreadr3  +  s=    	@HI1QqT$QqT5W56IIIs   'c           
      t    | i S | j                         D ci c]  \  }}|t        |fi |g c}}S c c}}w rq   rC   r  r   ru   r;   r(   s       r   parse_xread_resp3r7  1  sM    	EM^^EUEUzsE1122EU     4c           
          | si S t        | t              r.| j                         D ci c]  \  }}|t        |fi | c}}S | D ci c]  \  }}|t        |fi | c}}S c c}}w c c}}w )u   XREAD/XREADGROUP → unified ``dict[stream, list[tuple[id, dict]]]``.

    Accepts either RESP2 (``list[[stream, entries]]``) or RESP3
    (``dict[stream, entries]``) wire shape. Empty result is ``{}``.
    )rD   r   rC   r  )r   ru   r;   r(   streamr'  s         r   parse_xread_unifiedr;  9  s     	(D!GO~~GW
GWeC"54G44GW
 	
 NVMU/&'!'5W55X 
s   A#A)c           
      t    | sg S | j                         D cg c]  \  }}|t        |fi |g c}}S c c}}w )u   RESP3-wire XREAD/XREADGROUP → legacy RESP2 ``list[[stream, entries]]``.

    Empty result ``{}`` is converted to ``[]`` to match today's RESP2 shape.
    r5  r6  s       r   !parse_xread_resp3_to_resp2_legacyr=  J  sI    
 	EM^^EUEUzsE112EU  r8  c                     |j                  dd      rt        |       S | d   xs g D cg c]  \  }}|t        |      d }}}| d   | d   | d   |dS c c}}w )	Nparse_detailF   )rg   pendingr   r%   r   )rA  minmaxr(  )r   parse_xpending_ranger   )r   ru   r  pr(  s        r   parse_xpendingrF  V  sr    {{>5)#H--<DQK<M2<MN<MDAq!A/<MINA;{{	  Os   Ac           	      V    d}| D cg c]  }t        t        ||             c}S c c}w )N)
message_idconsumertime_since_deliveredtimes_delivered)r   r   )r   r,   r  s      r   rD  rD  b  s)    MA%-.XDQOX...s   &c                     | y t        |       S rq   r   r
   s    r   float_or_nonerM  g  s    ?r   c                     t        |       dk(  S NOKr   rt   s     r   bool_okrQ  m  s    !T))r   c                 V    | y |j                  d      rt        |       S t        |       S )Nas_score)r   r&   r   rt   s     r   
parse_zaddrT  q  s+    {{:Xx=r   c                    g }t        |       j                         D ]c  }i }|j                  d      }d }|D ]3  }d|v r|j                  dd      \  }}	|	||<   |}$||xx   d|z   z  cc<   5 |sS|j                  |       e |S )N r#   r%   )r   r4   r   r8   )
r   ru   clientsr0  client_dicttokenslast_keytokenr;   r(   s
             r   parse_client_listr\  y  s    G(#..0Ee|"[[a0
U#(C  H%u4%  NN;'! 1" Nr   c                 j    | D cg c]  }|t        |      nd  } }| xr t        |       xs i S c c}w rq   )r   rB   )r   ru   r  s      r   parse_config_getr^    s>    DLMHq1=Qd:HHM/h/525 Ns   0c                     | si S | j                         D ci c]"  \  }}|t        |      nd|t        |      nd$ c}}S c c}}w )u  RESP3-wire CONFIG GET → today's RESP2 ``dict[str, str]`` shape.

    On RESP3 the server returns a map; convert both keys and values via
    ``str_if_bytes`` so callers using ``r.config_get()["timeout"]``
    keep working when the wire is RESP3 with ``legacy_responses=True``.
    NrP   r6  s       r   &parse_config_get_resp3_to_resp2_legacyr`    sa     	
 #..*	 +JC !_S$#(#4L$	? +	  s   'Ac                 &    | \  }}t        |      |fS rq   r   )r   ru   cursorr  s       r   
parse_scanrc    s    IFAv;>r   c                     | \  }}|j                  dd      }|r|xs g }n|xr t        |      xs i }t        |      |fS )N	no_valuesF)r   rB   r   )r   ru   rb  r  re  payloads         r   parse_hscanrg    sJ    IFAK/I'r(a(.Bv;r   c           
          t        |j                  dt                    }| \  }}t        |      }t	        |      t        t        |t        ||                  fS Nr   )r   r   r&   r   r   rE   r   rs   )r   ru   r   rb  r  r   s         r   parse_zscanrj    sL    +GKK8I5,QROIFA	aBv;SS"%=>???r   c                     t        |j                  dt                    }| \  }}t        |      }t	        |      t        ||      D cg c]  \  }}| |t        |            g c}}fS c c}}w ri  )r   r   r&   r   r   r   )r   ru   r   rb  r  r   r(   r   s           r   parse_zscan_unifiedrl    so    +GKK8I5,QROIFA	aBv;CFr2;CN<5%e-.;   s   	A+c                 F    | D cg c]  }|t        |      nd  c}S c c}w rq   r   )r   ru   r   s      r   parse_zmscorern    s(    EMNXEE-E%L47XNNNs   c                 p    |j                  dd      rdndfd}| D cg c]
  } ||       c}S c c}w )Ndecode_responsesFrV      c                 X   | d   t        | d         t        | d         d}t        | d   t              r7j                  | d         |d<   t	        |       dk\  r| d   |d	<   | d
   |d<   |S | d   |d<   j                  | d         |d<   t	        |       dk\  r| d
   |d	<   | d   |d<   |S )Nr   r%   r   )id
start_timedurationr@  command      client_address   client_name
complexity   )r   rD   rE   joinr)  )r+   re   spaces     r   
parse_itemz%parse_slowlog_get.<locals>.parse_item  s    Qs47|TRSWV d1gt$ %

47 3F9 4yA~+/7'((,Q}%  $(7F<  %

47 3F9 4yA~+/7'((,Q}%r   )r   )r   ru   r  r+   r  s       @r   parse_slowlog_getr    s<    ;;159CtE. *22Jt222s   3c                    |j                  dd      rt        |       S |j                  dd      r|j                  dd      r=| d   D cg c].  }t        |d         gt        t        t        |dd             z   0 }}n)| d   D cg c]  }t        t        t        |             }}t        | d         |t        | d	         t        | d
         iS t        |       S c c}w c c}w )a  
    Parse the response from `STRALGO` command.
    Without modifiers the returned value is string.
    When LEN is given the command returns the length of the result
    (i.e integer).
    When IDX is given the command returns a dictionary with the LCS
    length and all the ranges in both the strings, start and end
    offset for each string, where there are matches.
    When WITHMATCHLEN is given, each array representing a match will
    also have the length of the match at the beginning of the array.
    r)  Fidxwithmatchlenr%   r/   Nr   r   r@  )r   r   rE   rs   tupler   )r   ru   matchmatchess       r   parse_stralgor    s     {{5% 8}{{5% ;;~u- &a[(E eBi."T#eU3BZ*@%AA(  
 =EQKHK5tCu-.KGH!%w!%s8A;'7
 	
 !!
 Is   	3C C"c                    |j                  dd      rt        |       S |j                  dd      r|j                  dd      r?| d   D cg c].  }t        |d         g|dd D cg c]  }t        |       c}z   0 }}}n+| d   D cg c]  }|D cg c]  }t        |       c} }}}t        | d         |t        | d	         t        | d
         iS t        |       S c c}w c c}}w c c}w c c}}w )z
    Parse STRALGO into the approved unified shape.

    The legacy parser returns tuple ranges for IDX responses. Unified
    responses use list ranges so RESP2 and RESP3 produce the same value.
    r)  Fr  r  r%   r/   Nr   r   r@  )r   r   rE   r   )r   ru   r  mr  s        r   parse_stralgo_unifiedr    s    {{5% 8}{{5% ;;~u- &a[(E U2Y U3BZ#@ZDGZ#@@(  
 >Fa[I[E/AQ/[GI!%w!%s8A;'7
 	
 !! $A
 0Is0   
C&$C!6C&		C1C,$C1!C&,C1c                 h   |j                  dd      rt        |       S |j                  dd      rt        | t              st	        |       S | j                  d| j                  dg             }| j                  d| j                  dd            }|j                  dd      r<|D cg c].  }t        |d	         g|d
d	 D cg c]  }t        |       c}z   0 }}}n(|D cg c]  }|D cg c]  }t        |       c} }}}|t        |      dS t	        |       S c c}w c c}}w c c}w c c}}w )zEParse RESP3 STRALGO into the same value as ``parse_stralgo_unified``.r)  Fr  r  s   matchess   lenr   r  r/   N)r  r)  )r   r   rD   r   r   rE   )r   ru   raw_matchesraw_lenr  r  r  s          r   parse_stralgo_resp3_unifiedr    s#   {{5% 8}{{5% (D)))ll9hll:r.JK,,uhll61&=>;;~u- )(E U2Y U3BZ#@ZDGZ#@@(  
 >II[E/AQ/[GI"3w<88!! $A
 0Is0   &D# DD#"	D.+D)=D.D#)D.c                 X    t        |       } t        d | j                         D              S )Nc              3   D   K   | ]  }|s|j                  d         ywr   r   )r   r:   s     r   r   z%parse_cluster_info.<locals>.<genexpr>1  s     J,ADT

3,As     )r   r   r4   rt   s     r   parse_cluster_infor  /  s&    H%HJH,?,?,AJJJr   c                 j   | j                  d      }| j                  d      d d \  }}}}}}}}	|j                  d      d   }
d|v r*d|v r&|j                  d      d   j                  d      d   nd}|||||||g g |	dk(  rd	nd
d
}t        |      dk\  rt        |dd        \  }}||c|d<   |d<   |
|fS )NrV     @r   r"   r%    	connectedTF)
node_idhostnamerf   	master_idlast_ping_sentlast_pong_rcvdepochslots
migrationsr  	   r  r  )r   r)  _parse_slots)r:   
line_itemsr  addrrf   r  pingpongr  r  ipr  	node_dictr  r  s                  r   _parse_node_liner  4  s    CJDHJJsOTVUVDWAGT5)T4		C	B36$;3$;tzz#q!'',Q/TVH&+5T5I :!(AB8z6;Z3	'Il3y=r   c                 P   g g }}| D ]  }d|v r.|dd j                  dd      \  }}|j                  ||dd       5d|v r.|dd j                  dd      \  }}|j                  ||dd       g|j                  d      D cg c]  }| }}|j                  |        ||fS c c}w )	Nz->-r%   r/   	migrating)slotr  r~   z-<-	importing-)r   r8   )slot_rangesr  r  s_rangeslot_iddst_node_idsrc_node_idsls           r   r  r  K  s    B:EG#*1R=#6#6ua#@ G[ [;O g#*1R=#6#6ua#@ G[ [;O %,MM#$67$6br$6G7LL!  * 8s   	B#c                 r    t        | t        t        f      r| j                         } t	        d | D              S )z
    @see: https://redis.io/commands/cluster-nodes  # string / bytes
    @see: https://redis.io/commands/cluster-replicas # list of string / bytes
    c              3   D   K   | ]  }t        t        |              y wrq   )r  r   )r   nodes     r   r   z&parse_cluster_nodes.<locals>.<genexpr>f  s     J d!34s    )rD   r   r   r4   r   rt   s     r   parse_cluster_nodesr  _  s1    
 (S%L)&&(JJJJr   c                 \   	 |d   s|d   r| S 	 t        | t              s| g}n| }|d   s|d   s|d   s|S t        d t        d}d g}|d	D cg c]  }||   s	||    c}z  }|D cg c]"  }t        t        d
 t        ||                  $ c}S # t         $ r | cY S w xY wc c}w c c}w )z
    Parse the response of 'GEOSEARCH', GEORADIUS' and 'GEORADIUSBYMEMBER'
    commands according to 'withdist', 'withhash' and 'withcoord' labels.
    store
store_distwithdist	withcoordwithhashc                 :    t        | d         t        | d         fS r   r   r   s    r   <lambda>z)parse_geosearch_generic.<locals>.<lambda>      r!uuRU| <r   r  r  r  c                     | S rq    rQ   s    r   r  z)parse_geosearch_generic.<locals>.<lambda>  s    1r   r  r  r  c                      | d   | d         S r   r  fvs    r   r  z)parse_geosearch_generic.<locals>.<lambda>      1ber   KeyErrorrD   rE   r&   r   rs   r   )r   ru   response_listcastfor  s          r   parse_geosearch_genericr  i  s    
7w|4 O	  5 h%!
 :w{';GJDW <D 
A@	O@aGAJ$q'@	OOACPQ=aD,c!Qi89=QQ-  * 
PQs#   B 
B$B$)'B)B! B!c                 Z   	 |d   s|d   r| S 	 t        | t              r| n| g}|d   s|d   s|d   s|S t        d t        d}d g}|d	D cg c]  }||   s	||    c}z  }|D cg c]"  }t        t        d
 t        ||                  $ c}S # t         $ r | cY S w xY wc c}w c c}w )zF
    Parse GEOSEARCH/GEORADIUS responses using tuple coordinates.
    r  r  r  r  r  c                 :    t        | d         t        | d         fS r   r   r  s    r   r  z1parse_geosearch_generic_unified.<locals>.<lambda>  r  r   r  c                     | S rq   r  r  s    r   r  z1parse_geosearch_generic_unified.<locals>.<lambda>  s    qr   r  c                      | d   | d         S r   r  r  s    r   r  z1parse_geosearch_generic_unified.<locals>.<lambda>  r  r   r  )r   ru   r  r  funcsr  r  s          r   parse_geosearch_generic_unifiedr    s    7w|4O  5
 !+8T :H
M:w{';GJDW <D
 ME	DSD!PQ
d1gDSSEGTU}!D,c%m<=}UU   TUs#   B 
B#B#('B(B B c                    i }| D ]  }i }t        |d         }||d<   t        |d         |d<   |d   D cg c]  }t        |       c}|d<   |d   |d<   |d	   |d
<   |d   |d<   t        |      dkD  r|d   D cg c]  }t        |       c}|d<   t        |      dkD  r|d   |d<   |d   |d<   |d   |d<   |||<    |S c c}w c c}w Nr   rg   r%   arityr   rf   r@  first_key_posrx  last_key_posrz  
step_countrw  acl_categoriesr}  tipsr  key_specificationsr  subcommandsr   r   r)  )r   ru   commandsrv  cmd_dictcmd_namerh   categorys           r   parse_commandr    s   H
+#
O<CAJGJD\$/JG$+AJ!#*1: !(w<!7>qz*7A8X&z*H%& w<!&qzHV-4QZH)*&-ajH]#%# $ O H
*   C:Cc                    i }| D ]  }i }t        |d         }||d<   t        |d         |d<   |d   D ch c]  }t        |       c}|d<   |d   |d<   |d	   |d
<   |d   |d<   t        |      dkD  r|d   D ch c]  }t        |       c}|d<   t        |      dkD  r|d   |d<   |d   |d<   |d   |d<   |||<    |S c c}w c c}w r  r  )r   ru   r  rv  r  r  rh   r0  s           r   parse_command_unifiedr    s   H
+#
O<CAJGJD\$/JG$+AJ!#*1: !(w<!CJ1:)N:a,q/:)NH%&w<!&qzHV-4QZH)*&-ajH]#%   O H
 *Or  c                 0   i }| D ]  }i }t        |d         }||d<   |d   |d<   |d   D ch c]  }t        |       c}|d<   |d   |d<   |d	   |d
<   |d   |d<   |d   |d<   t        |      dkD  r|d   |d<   |d   |d<   |d   |d<   |||<    |S c c}w r  )r   r)  )r   ru   r  rv  r  r  rh   s          r   parse_command_resp3r    s    H
+##AJ<CAJGJD\$/JG$+AJ!#*1: !(%,QZ!"w<!&qzHV-4QZH)*&-ajH]#%   O Hs   Bc           	      D    t        t        | dd d   | dd d               S )Nr   r   r%   )rE   r   rt   s     r   parse_pubsub_numsubr    s(    HQTTNHQTTN344r   c                 B    t        | t              r| S t        |       dk(  S rO  )rD   r   r   rt   s     r   parse_client_killr    s!    (C !T))r   c                    | y t        | t              rt        | d      }n,| j                         D ci c]  \  }}t	        |      | }}}t        t        t        |d               |d<   t        t        t        |d               |d<   t	        |d         |d<   t        |d   t              st        |d   t              r)t        t	        |d         j                  d            |d<   |d   dgk(  rg |d<   d	|v r]t        |d	   t              st        |d	   t              r)t        t	        |d	         j                  d            |d	<   |d	   dgk(  rg |d	<   d
|v r|d
   g k7  rDt        |d
   d   t              r.|d
   D cg c]  }t        t        t        |             c}|d
<   nV|d
   g k7  rN|d
   D cg c]8  }|j                         D ci c]  \  }}t	        |      t	        |       c}}: c}}}|d
<   g g }	}|d   j                  d      D ](  }
d|
v r|	j                  |
      n|j                  |
       * ||d<   |	|d<   d|d   v |d<   |S c c}}w c c}w c c}}w c c}}}w )NTrK   rf   	passwordsr  r   rV  r  channels	selectorsr   r  
categoriesonenabled)
rD   rE   rB   rC   r   rs   r   r   r   r8   )r   ru   r	  r;   r(   selectorr,   r)   r  r  rv  s              r   parse_acl_getuserr    s   (D!X48;C>>;KL;KZS%S!5(;KL \4=9:DMStK/@ABD#D$45D$v,$
4<(GLf6<<SABVF|tVTd:&,
4
;KU0S#Lj1A$B$H$H$MND
t#!Dd"z${2CA2F'MBF{BS!BShSx01BS!D +"$ !%[ 1! 1H ?Gnn>NO>Ndaa,q/1>NO 1!D rjH
#))#.&)Wn
'"(//':R /  D#Dd7m+DOKE M"!
 P!s#   I I <I+I%3I+%I+c                     | y t        | t              rZg }| D ]Q  }t        |dd      }|j                  dd      }t	        |      |d<   t        |d         |d<   |j                  |       S |S t        |       }|S )NTclient-infor  age-seconds)rD   rE   rB   r   parse_client_infor&   r8   rQ  )r   ru   r	  loglog_dataclient_infos         r   parse_acl_logr    s    (D!C$S$5H",,}b9K&7&DH]# ',H],C&DH]#KK!  K x Kr   c                 x   | yt        | t              st        |       S g }| D ]  }t        |t              r-|j	                         D ci c]  \  }}t        |      | }}}nt        |dd      }|j                  dd      }t        |      |d<   t        |d         |d<   |j                  |        |S c c}}w )u  RESP3-wire ACL LOG → today's RESP2 parsed shape.

    Each log entry arrives as a ``dict`` on RESP3 wire instead of a flat
    list of pairs; convert ``client-info`` from a string blob into the
    parsed ``dict`` and ``age-seconds`` to ``float`` so the Python shape
    matches what :func:`parse_acl_log` produces from RESP2 wire.

    Also used as the unified callback (Set D): the legacy and unified
    shapes coincide for ACL LOG.
    NTr  r  r  )rD   rE   rQ  r   rC   r   rB   r   r  r&   r8   )r   ru   r	  r  r,   r)   r  r   s           r   #parse_acl_log_resp3_to_resp2_legacyr  .  s     h%x  Dc4 7:yy{C{tq!Q*{HC$S$5Hll="5"3K"@"'(?"@H  K Ds   	B6c                    | yt        | t              st        |       S g }| D ]  }t        |t              r-|j	                         D ci c]  \  }}t        |      | }}}nt        |dd      }d|v rt        |d         |d<   d|v rt        |d         |d<   t        |j	                               D ]  \  }}|dvst        |      ||<    |j                  |        |S c c}}w )z4Parse RESP3 ACL LOG into the approved unified shape.NTr  r  )r  r  )
rD   rE   rQ  r   rC   r   rB   r&   r  r8   )	r   ru   r	  r-  r,   r)   r  r;   r(   s	            r   parse_acl_log_resp3_unifiedr  J  s    h%x  DeT"7<{{}E}tq!Q*}HE$UD$7HH$&+H],C&DH]#H$&78O&PH]#x~~/0JC88 ,U 3 1 	H  K Fs   	C#c                     t        | fi |}||S |j                  d      }|rEt        |d   t              r2|D cg c]#  }t	        t        |ddd   |ddd               % c}|d<   |S c c}w )u   ACL GETUSER → unified shape with selectors as ``list[dict]``.

    On RESP2 wire each selector arrives as a flat ``[k, v, k, v, …]``
    list; pair them into dicts to match the RESP3 wire shape.
    Nr  r   r   r%   )r  r   rD   rE   r   r   )r   ru   r	  r  r  s        r   parse_acl_getuser_unifiedr  a  s     X11D|%IZ	!d3FO
FO(DXadd^Xadd^45i
[ K
s   (A+c                    t        | fi |}||S |j                  d      }|rOt        |d   t              r<|D cg c])  }|j	                         D cg c]  }|D ]  }|  c}}+ c}}}|d<   |S c c}}w c c}}}w )u   RESP3-wire ACL GETUSER → today's RESP2 selectors as flat lists.

    Each selector arrives as a ``dict`` on RESP3 wire; flatten back to
    the interleaved ``[k, v, k, v, …]`` form produced by RESP2 wire.
    r  r   )r  r   rD   r   rC   )r   ru   r	  r  r  r   r+   s          r   'parse_acl_getuser_resp3_to_resp2_legacyr	  r  s     X11D|%IZ	!d3MV
MVHNN,<,bTT,<Y
[ K =
s   A;A5%A;5A;c                     i }t        |       j                         j                         D ]  }|j                  d      \  }} | ||<    dD ]  }||v st        ||         ||<    |S )zg
    Parsing client-info in ACL Log in following format.
    "key1=value1 key2=value2 key3=value3"
    r#   >   tot-memargv-mem	qbuf-freedbrs  ageoblollsubidleomempsubqbufmulti)r   stripr   r   )r(   r   r9   r;   int_keys        r   r  r    sw    
 KU#))+113ZZ_
U C 4
  k!#&{7';#<K #$ r   c                 L    |j                  d      r| S | xr t        |       dk(  S )z
    Handle SET result since GET argument is available since Redis 6.2.
    Parsing SET result into:
    - BOOL
    - String when GET argument is used
    r   rP  )r   r   rt   s     r   parse_set_resultr    s,     {{5 6X.$66r   c                 "   | yg }| D ]  }t        |t              r|j                  |       %t        |      }d|v rdnd}||v r3||   }|D cg c]  }t        |t              r|n
t        |      ! c}||<   |j                  |        |S c c}w )uG  FUNCTION LIST → unified ``list[dict]`` with bytes keys.

    Accepts either RESP2 wire (``list[list]`` of flat ``[k, v, k, v, …]``
    pairs, with the nested ``b"functions"`` value also a flat list of
    flat lists) or RESP3 wire (``list[dict]`` already in nested-map
    form). Both are normalised to ``list[dict]``.
    N	   functions	functions)rD   r   r8   rB   )r   ru   re   liblib_dictfunc_keyr  funcs           r   parse_function_list_unifiedr#    s     Fc4 MM# %#/8#;<x *I &"%D #4.M$4GG%"HX 	h  M"s   $Bc                    | yg }| D ]  }t        |t              s|j                  |       %g }|j                         D ]  \  }}|j                  |       |dk(  s|dk(  r[|j                  |D 	cg c];  }t        |t              r'|j                         D 	cg c]  }|D ]  }	|	  c}	}n|= c}	}}       ||j                  |        |j                  |        |S c c}	}w c c}	}}w )u  RESP3-wire FUNCTION LIST → today's RESP2 ``list[list]`` shape.

    Each library and each nested function arrives as a ``dict``; flatten
    them back to interleaved ``[k, v, k, v, …]`` lists so the Python
    shape matches what RESP2 wire produces natively.
    Nr  r  )rD   r   r8   rC   )
r   ru   re   r  r   r;   r(   r"  r   r+   s
             r   )parse_function_list_resp3_to_resp2_legacyr%    s     F#t$MM#))+JCKKl"c[&8
 %*	 %*D &dD1 )-

D"D!" %*	 E" & 	d% & M Es   1(C)C#)C)#C)c                     | y| D cg c]L  }t        |t              r-|j                         D ci c]  \  }}t        |      | c}}nt	        |d      N c}}}S c c}}w c c}}}w )u   CLUSTER LINKS → unified ``list[dict]`` with string keys.

    Accepts either RESP2 wire (``list[list]`` of flat pairs) or RESP3
    wire (``list[dict]``). Both are normalised to ``list[dict]``.
    NTrK   )rD   r   rC   r   rB   )r   ru   r+   r,   r)   s        r   parse_cluster_links_unifiedr'    sx     
 	 D dD! )-

51a!	54T2	3 	 5s   (A&A A& A&c                     | y| D cg c];  }t        |t              r'|j                         D cg c]  }|D ]  }|  c}}n|= c}}}S c c}}w c c}}}w )u   RESP3-wire CLUSTER LINKS → today's RESP2 ``list[list]`` shape.

    Each link arrives as a ``dict`` with bytes keys; flatten back to
    interleaved ``[k, v, k, v, …]`` lists so the Python shape matches
    what RESP2 wire produces natively.
    N)rD   r   rC   )r   ru   linkr   r+   s        r   )parse_cluster_links_resp3_to_resp2_legacyr*    sd      D 9C48N

4"4TXX 4s   (AAAAc                 J    t         j                  | j                         |      S rq   )r   fromkeysr   )
key_stringcallbacks     r   string_keys_to_dictr/    s    ==))+X66r   r%   )_RedisCallbacks_RedisCallbacksRESP2_RedisCallbacksRESP2Unified_RedisCallbacksRESP3_RedisCallbacksRESP3Unified!_RedisCallbacksRESP3toRESP2Legacyget_response_callbacks)FF)zr   redis.utilsr   r   r   r<   rI   rL   rN   rR   r   rm   rd   ri   ro   rv   rz   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   rB   rl   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r  r  r  r  r  r  r  r  r   r"  r$  r1  r3  r7  r;  r=  rF  rD  rM  rQ  rT  r\  r^  r`  rc  rg  rj  rl  rn  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r	  r  r  r#  r%  r'  r*  r/  response_callbacksr0  r1  r2  r3  r4  r5  r6  r  r   r   <module>r9     s?    $5$0f
VsC s 	
 C # # s c S 3 3 # 3   c!" C#$ / 6 %=PNY@!&,	3
37D71&NP
>P9P&::< YY(:5<'=>J"		/
*,6
"
 @O
3:":"0"(K
.(K!RHV2.**5*(V$8.""@76@ 7  r   