502 lines
18 KiB
Python
502 lines
18 KiB
Python
|
|
"""Response-callback dictionaries and the protocol/legacy selector.
|
||
|
|
|
||
|
|
This module is the single source of truth for the mapping between Redis
|
||
|
|
command names and the Python-side callbacks that post-process raw parser
|
||
|
|
output into user-facing values.
|
||
|
|
|
||
|
|
Six dictionaries are defined:
|
||
|
|
|
||
|
|
* ``_RedisCallbacks`` — entries that produce the same Python value
|
||
|
|
regardless of wire protocol or legacy-response selection.
|
||
|
|
* ``_RedisCallbacksRESP2`` — RESP2 wire, legacy Python shapes.
|
||
|
|
* ``_RedisCallbacksRESP3`` — RESP3 wire, Python shapes from the previous
|
||
|
|
RESP3 callbacks.
|
||
|
|
* ``_RedisCallbacksRESP2Unified`` — RESP2 wire, unified Python shapes
|
||
|
|
(``legacy_responses=False``).
|
||
|
|
* ``_RedisCallbacksRESP3Unified`` — RESP3 wire, unified Python shapes
|
||
|
|
(``legacy_responses=False``).
|
||
|
|
* ``_RedisCallbacksRESP3toRESP2Legacy`` — RESP3 wire converted back to the
|
||
|
|
legacy RESP2 Python shapes for users who keep ``legacy_responses=True``
|
||
|
|
on a RESP3 connection.
|
||
|
|
|
||
|
|
``get_response_callbacks`` merges ``_RedisCallbacks`` with the appropriate
|
||
|
|
protocol-specific overlay. Callers wrap the returned dict in
|
||
|
|
``CaseInsensitiveDict``.
|
||
|
|
"""
|
||
|
|
|
||
|
|
from typing import Any, Callable, Optional
|
||
|
|
|
||
|
|
from redis.utils import str_if_bytes
|
||
|
|
|
||
|
|
from .helpers import (
|
||
|
|
bool_ok,
|
||
|
|
bzpop_score_resp3_to_resp2_legacy,
|
||
|
|
bzpop_score_unified,
|
||
|
|
float_or_none,
|
||
|
|
hrandfield_resp3_to_resp2_legacy,
|
||
|
|
hrandfield_unified,
|
||
|
|
pairs_to_dict,
|
||
|
|
parse_acl_getuser,
|
||
|
|
parse_acl_getuser_resp3_to_resp2_legacy,
|
||
|
|
parse_acl_getuser_unified,
|
||
|
|
parse_acl_log,
|
||
|
|
parse_acl_log_resp3_to_resp2_legacy,
|
||
|
|
parse_acl_log_resp3_unified,
|
||
|
|
parse_arinfo,
|
||
|
|
parse_client_info,
|
||
|
|
parse_client_kill,
|
||
|
|
parse_client_list,
|
||
|
|
parse_client_trackinginfo_resp3_to_resp2_legacy,
|
||
|
|
parse_client_trackinginfo_unified,
|
||
|
|
parse_cluster_info,
|
||
|
|
parse_cluster_links_resp3_to_resp2_legacy,
|
||
|
|
parse_cluster_links_unified,
|
||
|
|
parse_cluster_nodes,
|
||
|
|
parse_command,
|
||
|
|
parse_command_resp3,
|
||
|
|
parse_command_unified,
|
||
|
|
parse_config_get,
|
||
|
|
parse_config_get_resp3_to_resp2_legacy,
|
||
|
|
parse_debug_object,
|
||
|
|
parse_function_list_resp3_to_resp2_legacy,
|
||
|
|
parse_function_list_unified,
|
||
|
|
parse_geopos_resp3_to_resp2_legacy,
|
||
|
|
parse_geopos_unified,
|
||
|
|
parse_geosearch_generic,
|
||
|
|
parse_geosearch_generic_unified,
|
||
|
|
parse_hscan,
|
||
|
|
parse_info,
|
||
|
|
parse_lcs_idx_resp3_to_resp2_legacy,
|
||
|
|
parse_lcs_idx_unified,
|
||
|
|
parse_list_of_dicts,
|
||
|
|
parse_list_of_dicts_resp3,
|
||
|
|
parse_memory_stats,
|
||
|
|
parse_memory_stats_resp3,
|
||
|
|
parse_memory_stats_unified,
|
||
|
|
parse_pubsub_numsub,
|
||
|
|
parse_scan,
|
||
|
|
parse_sentinel_get_master,
|
||
|
|
parse_sentinel_master,
|
||
|
|
parse_sentinel_master_resp3_to_resp2_legacy,
|
||
|
|
parse_sentinel_master_unified,
|
||
|
|
parse_sentinel_master_unified_resp3,
|
||
|
|
parse_sentinel_masters,
|
||
|
|
parse_sentinel_masters_resp3,
|
||
|
|
parse_sentinel_masters_resp3_to_resp2_legacy,
|
||
|
|
parse_sentinel_masters_unified,
|
||
|
|
parse_sentinel_masters_unified_resp3,
|
||
|
|
parse_sentinel_slaves_and_sentinels,
|
||
|
|
parse_sentinel_slaves_and_sentinels_resp3,
|
||
|
|
parse_sentinel_slaves_and_sentinels_resp3_to_resp2_legacy,
|
||
|
|
parse_sentinel_slaves_and_sentinels_unified,
|
||
|
|
parse_sentinel_slaves_and_sentinels_unified_resp3,
|
||
|
|
parse_sentinel_state_resp3,
|
||
|
|
parse_set_result,
|
||
|
|
parse_slowlog_get,
|
||
|
|
parse_stralgo,
|
||
|
|
parse_stralgo_resp3_unified,
|
||
|
|
parse_stralgo_unified,
|
||
|
|
parse_stream_list,
|
||
|
|
parse_xautoclaim,
|
||
|
|
parse_xclaim,
|
||
|
|
parse_xinfo_stream,
|
||
|
|
parse_xpending,
|
||
|
|
parse_xread,
|
||
|
|
parse_xread_resp3,
|
||
|
|
parse_xread_resp3_to_resp2_legacy,
|
||
|
|
parse_xread_unified,
|
||
|
|
parse_zadd,
|
||
|
|
parse_zmscore,
|
||
|
|
parse_zscan,
|
||
|
|
parse_zscan_unified,
|
||
|
|
sort_return_tuples,
|
||
|
|
string_keys_to_dict,
|
||
|
|
timestamp_to_datetime,
|
||
|
|
zmpop_resp3_to_resp2_legacy,
|
||
|
|
zmpop_unified,
|
||
|
|
zpop_score_pairs,
|
||
|
|
zpop_score_pairs_resp3_to_resp2_legacy,
|
||
|
|
zpop_score_pairs_resp3_unified,
|
||
|
|
zpop_score_pairs_unified,
|
||
|
|
zset_score_for_rank,
|
||
|
|
zset_score_for_rank_resp3,
|
||
|
|
zset_score_for_rank_resp3_to_resp2_legacy,
|
||
|
|
zset_score_for_rank_unified,
|
||
|
|
zset_score_pairs,
|
||
|
|
zset_score_pairs_resp3,
|
||
|
|
zset_score_pairs_resp3_to_resp2_legacy,
|
||
|
|
zset_score_pairs_resp3_to_resp2_legacy_flat,
|
||
|
|
zset_score_pairs_unified,
|
||
|
|
)
|
||
|
|
|
||
|
|
_RedisCallbacks = {
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"AUTH COPY EXPIRE EXPIREAT HEXISTS HMSET MOVE MSETNX PERSIST PSETEX "
|
||
|
|
"PEXPIRE PEXPIREAT RENAMENX SETEX SETNX SMOVE",
|
||
|
|
bool,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict("HINCRBYFLOAT INCRBYFLOAT", float),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"ASKING FLUSHALL FLUSHDB LSET LTRIM MSET PFMERGE READONLY READWRITE "
|
||
|
|
"RENAME SAVE SELECT SHUTDOWN SLAVEOF SWAPDB WATCH UNWATCH",
|
||
|
|
bool_ok,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict("XREAD XREADGROUP", parse_xread),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"GEORADIUS GEORADIUSBYMEMBER GEOSEARCH",
|
||
|
|
parse_geosearch_generic,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict("XRANGE XREVRANGE", parse_stream_list),
|
||
|
|
"ACL GETUSER": parse_acl_getuser,
|
||
|
|
"ACL LOAD": bool_ok,
|
||
|
|
"ACL LOG": parse_acl_log,
|
||
|
|
"ACL SETUSER": bool_ok,
|
||
|
|
"ACL SAVE": bool_ok,
|
||
|
|
"CLIENT INFO": parse_client_info,
|
||
|
|
"CLIENT KILL": parse_client_kill,
|
||
|
|
"CLIENT LIST": parse_client_list,
|
||
|
|
"CLIENT PAUSE": bool_ok,
|
||
|
|
"CLIENT SETINFO": bool_ok,
|
||
|
|
"CLIENT SETNAME": bool_ok,
|
||
|
|
"CLIENT UNBLOCK": bool,
|
||
|
|
"CLUSTER ADDSLOTS": bool_ok,
|
||
|
|
"CLUSTER ADDSLOTSRANGE": bool_ok,
|
||
|
|
"CLUSTER DELSLOTS": bool_ok,
|
||
|
|
"CLUSTER DELSLOTSRANGE": bool_ok,
|
||
|
|
"CLUSTER FAILOVER": bool_ok,
|
||
|
|
"CLUSTER FORGET": bool_ok,
|
||
|
|
"CLUSTER INFO": parse_cluster_info,
|
||
|
|
"CLUSTER MEET": bool_ok,
|
||
|
|
"CLUSTER NODES": parse_cluster_nodes,
|
||
|
|
"CLUSTER REPLICAS": parse_cluster_nodes,
|
||
|
|
"CLUSTER REPLICATE": bool_ok,
|
||
|
|
"CLUSTER RESET": bool_ok,
|
||
|
|
"CLUSTER SAVECONFIG": bool_ok,
|
||
|
|
"CLUSTER SET-CONFIG-EPOCH": bool_ok,
|
||
|
|
"CLUSTER SETSLOT": bool_ok,
|
||
|
|
"CLUSTER SLAVES": parse_cluster_nodes,
|
||
|
|
"COMMAND": parse_command,
|
||
|
|
"CONFIG RESETSTAT": bool_ok,
|
||
|
|
"CONFIG SET": bool_ok,
|
||
|
|
"FUNCTION DELETE": bool_ok,
|
||
|
|
"FUNCTION FLUSH": bool_ok,
|
||
|
|
"FUNCTION RESTORE": bool_ok,
|
||
|
|
"GEODIST": float_or_none,
|
||
|
|
"HSCAN": parse_hscan,
|
||
|
|
"INFO": parse_info,
|
||
|
|
"LASTSAVE": timestamp_to_datetime,
|
||
|
|
"MEMORY PURGE": bool_ok,
|
||
|
|
"MODULE LOAD": bool,
|
||
|
|
"MODULE UNLOAD": bool,
|
||
|
|
"PING": lambda r: str_if_bytes(r) == "PONG",
|
||
|
|
"PUBSUB NUMSUB": parse_pubsub_numsub,
|
||
|
|
"PUBSUB SHARDNUMSUB": parse_pubsub_numsub,
|
||
|
|
"QUIT": bool_ok,
|
||
|
|
"SET": parse_set_result,
|
||
|
|
"SCAN": parse_scan,
|
||
|
|
"SCRIPT EXISTS": lambda r: list(map(bool, r)),
|
||
|
|
"SCRIPT FLUSH": bool_ok,
|
||
|
|
"SCRIPT KILL": bool_ok,
|
||
|
|
"SCRIPT LOAD": str_if_bytes,
|
||
|
|
"SENTINEL CKQUORUM": bool_ok,
|
||
|
|
"SENTINEL FAILOVER": bool_ok,
|
||
|
|
"SENTINEL FLUSHCONFIG": bool_ok,
|
||
|
|
"SENTINEL GET-MASTER-ADDR-BY-NAME": parse_sentinel_get_master,
|
||
|
|
"SENTINEL MONITOR": bool_ok,
|
||
|
|
"SENTINEL RESET": bool_ok,
|
||
|
|
"SENTINEL REMOVE": bool_ok,
|
||
|
|
"SENTINEL SET": bool_ok,
|
||
|
|
"SLOWLOG GET": parse_slowlog_get,
|
||
|
|
"SLOWLOG RESET": bool_ok,
|
||
|
|
"SORT": sort_return_tuples,
|
||
|
|
"SSCAN": parse_scan,
|
||
|
|
"TIME": lambda x: (int(x[0]), int(x[1])),
|
||
|
|
"XAUTOCLAIM": parse_xautoclaim,
|
||
|
|
"XCLAIM": parse_xclaim,
|
||
|
|
"XGROUP CREATE": bool_ok,
|
||
|
|
"XGROUP DESTROY": bool,
|
||
|
|
"XGROUP SETID": bool_ok,
|
||
|
|
"ARINFO": parse_arinfo,
|
||
|
|
"XINFO STREAM": parse_xinfo_stream,
|
||
|
|
"XPENDING": parse_xpending,
|
||
|
|
"ZSCAN": parse_zscan,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
_RedisCallbacksRESP2 = {
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"SDIFF SINTER SMEMBERS SUNION", lambda r: r and set(r) or set()
|
||
|
|
),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"ZINTER ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION",
|
||
|
|
zset_score_pairs,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict("ZPOPMAX ZPOPMIN", zpop_score_pairs),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"ZREVRANK ZRANK",
|
||
|
|
zset_score_for_rank,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict("ZINCRBY ZSCORE", float_or_none),
|
||
|
|
**string_keys_to_dict("BGREWRITEAOF BGSAVE", lambda r: True),
|
||
|
|
**string_keys_to_dict("BLPOP BRPOP", lambda r: r and tuple(r) or None),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"BZPOPMAX BZPOPMIN", lambda r: r and (r[0], r[1], float(r[2])) or None
|
||
|
|
),
|
||
|
|
"ACL CAT": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"ACL GENPASS": str_if_bytes,
|
||
|
|
"ACL HELP": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"ACL LIST": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"ACL USERS": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"ACL WHOAMI": str_if_bytes,
|
||
|
|
"CLIENT GETNAME": str_if_bytes,
|
||
|
|
"CLIENT TRACKINGINFO": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"CLUSTER GETKEYSINSLOT": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"COMMAND GETKEYS": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"CONFIG GET": parse_config_get,
|
||
|
|
"DEBUG OBJECT": parse_debug_object,
|
||
|
|
"GEOHASH": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"GEOPOS": lambda r: list(
|
||
|
|
map(lambda ll: (float(ll[0]), float(ll[1])) if ll is not None else None, r)
|
||
|
|
),
|
||
|
|
"HGETALL": lambda r: r and pairs_to_dict(r) or {},
|
||
|
|
"HOTKEYS GET": lambda r: [pairs_to_dict(m) for m in r],
|
||
|
|
"MEMORY STATS": parse_memory_stats,
|
||
|
|
"MODULE LIST": lambda r: [pairs_to_dict(m) for m in r],
|
||
|
|
"RESET": str_if_bytes,
|
||
|
|
"SENTINEL MASTER": parse_sentinel_master,
|
||
|
|
"SENTINEL MASTERS": parse_sentinel_masters,
|
||
|
|
"SENTINEL SENTINELS": parse_sentinel_slaves_and_sentinels,
|
||
|
|
"SENTINEL SLAVES": parse_sentinel_slaves_and_sentinels,
|
||
|
|
"STRALGO": parse_stralgo,
|
||
|
|
"XINFO CONSUMERS": parse_list_of_dicts,
|
||
|
|
"XINFO GROUPS": parse_list_of_dicts,
|
||
|
|
"ZADD": parse_zadd,
|
||
|
|
"ZMSCORE": parse_zmscore,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
_RedisCallbacksRESP3 = {
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"SDIFF SINTER SMEMBERS SUNION", lambda r: r and set(r) or set()
|
||
|
|
),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"ZRANGE ZINTER ZPOPMAX ZPOPMIN HGETALL XREADGROUP",
|
||
|
|
lambda r, **kwargs: r,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION",
|
||
|
|
zset_score_pairs_resp3,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"ZREVRANK ZRANK",
|
||
|
|
zset_score_for_rank_resp3,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict("XREAD XREADGROUP", parse_xread_resp3),
|
||
|
|
"ACL LOG": lambda r: (
|
||
|
|
[
|
||
|
|
{str_if_bytes(key): str_if_bytes(value) for key, value in x.items()}
|
||
|
|
for x in r
|
||
|
|
]
|
||
|
|
if isinstance(r, list)
|
||
|
|
else bool_ok(r)
|
||
|
|
),
|
||
|
|
"COMMAND": parse_command_resp3,
|
||
|
|
"CONFIG GET": parse_config_get_resp3_to_resp2_legacy,
|
||
|
|
"MEMORY STATS": parse_memory_stats_resp3,
|
||
|
|
"SENTINEL MASTER": parse_sentinel_state_resp3,
|
||
|
|
"SENTINEL MASTERS": parse_sentinel_masters_resp3,
|
||
|
|
"SENTINEL SENTINELS": parse_sentinel_slaves_and_sentinels_resp3,
|
||
|
|
"SENTINEL SLAVES": parse_sentinel_slaves_and_sentinels_resp3,
|
||
|
|
"STRALGO": lambda r, **options: (
|
||
|
|
{str_if_bytes(key): str_if_bytes(value) for key, value in r.items()}
|
||
|
|
if isinstance(r, dict)
|
||
|
|
else str_if_bytes(r)
|
||
|
|
),
|
||
|
|
"XINFO CONSUMERS": parse_list_of_dicts_resp3,
|
||
|
|
"XINFO GROUPS": parse_list_of_dicts_resp3,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
# RESP2 wire, unified response shapes (``legacy_responses=False``).
|
||
|
|
_RedisCallbacksRESP2Unified: dict[str, Callable[..., Any]] = {
|
||
|
|
**_RedisCallbacksRESP2,
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"ZDIFF ZINTER ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION",
|
||
|
|
zset_score_pairs_unified,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"ZPOPMAX ZPOPMIN",
|
||
|
|
zpop_score_pairs_unified,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"ZREVRANK ZRANK",
|
||
|
|
zset_score_for_rank_unified,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"BZPOPMAX BZPOPMIN",
|
||
|
|
bzpop_score_unified,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict("XREAD XREADGROUP", parse_xread_unified),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"GEORADIUS GEORADIUSBYMEMBER GEOSEARCH",
|
||
|
|
parse_geosearch_generic_unified,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict("BLPOP BRPOP", lambda r: r or None),
|
||
|
|
**string_keys_to_dict("ZMPOP BZMPOP", zmpop_unified),
|
||
|
|
"ZSCAN": parse_zscan_unified,
|
||
|
|
"ZRANDMEMBER": zset_score_pairs_unified,
|
||
|
|
"HRANDFIELD": hrandfield_unified,
|
||
|
|
"ACL GETUSER": parse_acl_getuser_unified,
|
||
|
|
"CLIENT TRACKINGINFO": parse_client_trackinginfo_unified,
|
||
|
|
"CLUSTER GETKEYSINSLOT": lambda r, **kwargs: r,
|
||
|
|
"CLUSTER LINKS": parse_cluster_links_unified,
|
||
|
|
"COMMAND": parse_command_unified,
|
||
|
|
"COMMAND GETKEYS": lambda r, **kwargs: r,
|
||
|
|
"FUNCTION LIST": parse_function_list_unified,
|
||
|
|
"GEOPOS": parse_geopos_unified,
|
||
|
|
"LCS": parse_lcs_idx_unified,
|
||
|
|
"MEMORY STATS": parse_memory_stats_unified,
|
||
|
|
"SENTINEL MASTER": parse_sentinel_master_unified,
|
||
|
|
"SENTINEL MASTERS": parse_sentinel_masters_unified,
|
||
|
|
"SENTINEL SENTINELS": parse_sentinel_slaves_and_sentinels_unified,
|
||
|
|
"SENTINEL SLAVES": parse_sentinel_slaves_and_sentinels_unified,
|
||
|
|
"STRALGO": parse_stralgo_unified,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
# RESP3 wire, unified response shapes (``legacy_responses=False``).
|
||
|
|
_RedisCallbacksRESP3Unified: dict[str, Callable[..., Any]] = {
|
||
|
|
**_RedisCallbacksRESP3,
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"ZDIFF ZINTER ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION",
|
||
|
|
zset_score_pairs_resp3,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"ZPOPMAX ZPOPMIN",
|
||
|
|
zpop_score_pairs_resp3_unified,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"BZPOPMAX BZPOPMIN",
|
||
|
|
bzpop_score_unified,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict("XREAD XREADGROUP", parse_xread_unified),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"GEORADIUS GEORADIUSBYMEMBER GEOSEARCH",
|
||
|
|
parse_geosearch_generic_unified,
|
||
|
|
),
|
||
|
|
"ZSCAN": parse_zscan_unified,
|
||
|
|
"ZRANDMEMBER": zset_score_pairs_resp3,
|
||
|
|
"ACL CAT": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"ACL GENPASS": str_if_bytes,
|
||
|
|
"ACL HELP": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"ACL LIST": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"ACL LOG": parse_acl_log_resp3_unified,
|
||
|
|
"ACL USERS": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"ACL WHOAMI": str_if_bytes,
|
||
|
|
"CLIENT GETNAME": str_if_bytes,
|
||
|
|
"CLIENT TRACKINGINFO": parse_client_trackinginfo_unified,
|
||
|
|
"CLUSTER LINKS": parse_cluster_links_unified,
|
||
|
|
"COMMAND": parse_command_unified,
|
||
|
|
"FUNCTION LIST": parse_function_list_unified,
|
||
|
|
"GEOHASH": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"LCS": parse_lcs_idx_unified,
|
||
|
|
"RESET": str_if_bytes,
|
||
|
|
"SENTINEL MASTER": parse_sentinel_master_unified_resp3,
|
||
|
|
"SENTINEL MASTERS": parse_sentinel_masters_unified_resp3,
|
||
|
|
"SENTINEL SENTINELS": parse_sentinel_slaves_and_sentinels_unified_resp3,
|
||
|
|
"SENTINEL SLAVES": parse_sentinel_slaves_and_sentinels_unified_resp3,
|
||
|
|
"STRALGO": parse_stralgo_resp3_unified,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
# RESP3 wire converted back to the legacy RESP2 Python shapes. Only the
|
||
|
|
# entries needed to undo RESP3-side differences are listed; everything
|
||
|
|
# else falls through to ``_RedisCallbacks``. Scores are re-encoded to bytes
|
||
|
|
# before being passed to ``score_cast_func`` so the callable observes the
|
||
|
|
# same input type it would on a RESP2 connection.
|
||
|
|
_RedisCallbacksRESP3toRESP2Legacy: dict[str, Callable[..., Any]] = {
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"SDIFF SINTER SMEMBERS SUNION", lambda r: r and set(r) or set()
|
||
|
|
),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"ZINTER ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION",
|
||
|
|
zset_score_pairs_resp3_to_resp2_legacy,
|
||
|
|
),
|
||
|
|
"ZDIFF": zset_score_pairs_resp3_to_resp2_legacy_flat,
|
||
|
|
"ZRANDMEMBER": zset_score_pairs_resp3_to_resp2_legacy_flat,
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"ZPOPMAX ZPOPMIN",
|
||
|
|
zpop_score_pairs_resp3_to_resp2_legacy,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"BZPOPMAX BZPOPMIN",
|
||
|
|
bzpop_score_resp3_to_resp2_legacy,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict(
|
||
|
|
"ZREVRANK ZRANK",
|
||
|
|
zset_score_for_rank_resp3_to_resp2_legacy,
|
||
|
|
),
|
||
|
|
**string_keys_to_dict("BGREWRITEAOF BGSAVE", lambda r: True),
|
||
|
|
**string_keys_to_dict("XREAD XREADGROUP", parse_xread_resp3_to_resp2_legacy),
|
||
|
|
**string_keys_to_dict("BLPOP BRPOP", lambda r: r and tuple(r) or None),
|
||
|
|
**string_keys_to_dict("ZMPOP BZMPOP", zmpop_resp3_to_resp2_legacy),
|
||
|
|
"HRANDFIELD": hrandfield_resp3_to_resp2_legacy,
|
||
|
|
"ACL CAT": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"ACL GENPASS": str_if_bytes,
|
||
|
|
"ACL GETUSER": parse_acl_getuser_resp3_to_resp2_legacy,
|
||
|
|
"ACL HELP": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"ACL LIST": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"ACL LOG": parse_acl_log_resp3_to_resp2_legacy,
|
||
|
|
"ACL USERS": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"ACL WHOAMI": str_if_bytes,
|
||
|
|
"CLIENT GETNAME": str_if_bytes,
|
||
|
|
"CLIENT TRACKINGINFO": parse_client_trackinginfo_resp3_to_resp2_legacy,
|
||
|
|
"CLUSTER GETKEYSINSLOT": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"CLUSTER LINKS": parse_cluster_links_resp3_to_resp2_legacy,
|
||
|
|
"COMMAND GETKEYS": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"CONFIG GET": parse_config_get_resp3_to_resp2_legacy,
|
||
|
|
"DEBUG OBJECT": parse_debug_object,
|
||
|
|
"FUNCTION LIST": parse_function_list_resp3_to_resp2_legacy,
|
||
|
|
"GEOHASH": lambda r: list(map(str_if_bytes, r)),
|
||
|
|
"GEOPOS": parse_geopos_resp3_to_resp2_legacy,
|
||
|
|
"LCS": parse_lcs_idx_resp3_to_resp2_legacy,
|
||
|
|
"MEMORY STATS": parse_memory_stats_resp3,
|
||
|
|
"RESET": str_if_bytes,
|
||
|
|
"SENTINEL MASTER": parse_sentinel_master_resp3_to_resp2_legacy,
|
||
|
|
"SENTINEL MASTERS": parse_sentinel_masters_resp3_to_resp2_legacy,
|
||
|
|
"SENTINEL SENTINELS": parse_sentinel_slaves_and_sentinels_resp3_to_resp2_legacy,
|
||
|
|
"SENTINEL SLAVES": parse_sentinel_slaves_and_sentinels_resp3_to_resp2_legacy,
|
||
|
|
"XINFO CONSUMERS": parse_list_of_dicts_resp3,
|
||
|
|
"XINFO GROUPS": parse_list_of_dicts_resp3,
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def get_response_callbacks(
|
||
|
|
user_protocol: Optional[int],
|
||
|
|
legacy_responses: bool,
|
||
|
|
) -> dict[str, Callable[..., Any]]:
|
||
|
|
"""Return the merged callback dict for the given (protocol, legacy)
|
||
|
|
combination.
|
||
|
|
|
||
|
|
``user_protocol`` is the value the user supplied to the client
|
||
|
|
constructor (``None`` means "not specified"). ``legacy_responses``
|
||
|
|
defaults to ``True`` and selects today's RESP2-style Python shapes
|
||
|
|
even when the wire protocol is RESP3.
|
||
|
|
|
||
|
|
Callers wrap the returned dict in ``CaseInsensitiveDict``.
|
||
|
|
"""
|
||
|
|
callbacks: dict[str, Callable[..., Any]] = dict(_RedisCallbacks)
|
||
|
|
if legacy_responses:
|
||
|
|
if user_protocol is None:
|
||
|
|
callbacks.update(_RedisCallbacksRESP3toRESP2Legacy)
|
||
|
|
elif user_protocol in (3, "3"):
|
||
|
|
callbacks.update(_RedisCallbacksRESP3)
|
||
|
|
else:
|
||
|
|
callbacks.update(_RedisCallbacksRESP2)
|
||
|
|
else:
|
||
|
|
if user_protocol is None or user_protocol in (3, "3"):
|
||
|
|
callbacks.update(_RedisCallbacksRESP3Unified)
|
||
|
|
else:
|
||
|
|
callbacks.update(_RedisCallbacksRESP2Unified)
|
||
|
|
return callbacks
|