Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/redis/_parsers/response_callbacks.py: 52%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

23 statements  

1"""Response-callback dictionaries and the protocol/legacy selector. 

2 

3This module is the single source of truth for the mapping between Redis 

4command names and the Python-side callbacks that post-process raw parser 

5output into user-facing values. 

6 

7Six dictionaries are defined: 

8 

9* ``_RedisCallbacks`` — entries that produce the same Python value 

10 regardless of wire protocol or legacy-response selection. 

11* ``_RedisCallbacksRESP2`` — RESP2 wire, legacy Python shapes. 

12* ``_RedisCallbacksRESP3`` — RESP3 wire, Python shapes from the previous 

13 RESP3 callbacks. 

14* ``_RedisCallbacksRESP2Unified`` — RESP2 wire, unified Python shapes 

15 (``legacy_responses=False``). 

16* ``_RedisCallbacksRESP3Unified`` — RESP3 wire, unified Python shapes 

17 (``legacy_responses=False``). 

18* ``_RedisCallbacksRESP3toRESP2Legacy`` — RESP3 wire converted back to the 

19 legacy RESP2 Python shapes for users who keep ``legacy_responses=True`` 

20 on a RESP3 connection. 

21 

22``get_response_callbacks`` merges ``_RedisCallbacks`` with the appropriate 

23protocol-specific overlay. Callers wrap the returned dict in 

24``CaseInsensitiveDict``. 

25""" 

26 

27from typing import Any, Callable, Optional 

28 

29from redis.himport import ( 

30 HIMPORT_DISCARD, 

31 HIMPORT_DISCARDALL, 

32 HIMPORT_PREPARE, 

33 HIMPORT_SET, 

34) 

35from redis.utils import str_if_bytes 

36 

37from .helpers import ( 

38 bool_ok, 

39 bzpop_score_resp3_to_resp2_legacy, 

40 bzpop_score_unified, 

41 float_or_none, 

42 hrandfield_resp3_to_resp2_legacy, 

43 hrandfield_unified, 

44 pairs_to_dict, 

45 parse_acl_getuser, 

46 parse_acl_getuser_resp3_to_resp2_legacy, 

47 parse_acl_getuser_unified, 

48 parse_acl_log, 

49 parse_acl_log_resp3_to_resp2_legacy, 

50 parse_acl_log_resp3_unified, 

51 parse_arinfo, 

52 parse_client_info, 

53 parse_client_kill, 

54 parse_client_list, 

55 parse_client_trackinginfo_resp3_to_resp2_legacy, 

56 parse_client_trackinginfo_unified, 

57 parse_cluster_info, 

58 parse_cluster_links_resp3_to_resp2_legacy, 

59 parse_cluster_links_unified, 

60 parse_cluster_nodes, 

61 parse_command, 

62 parse_command_resp3, 

63 parse_command_unified, 

64 parse_config_get, 

65 parse_config_get_resp3_to_resp2_legacy, 

66 parse_debug_object, 

67 parse_function_list_resp3_to_resp2_legacy, 

68 parse_function_list_unified, 

69 parse_geopos_resp3_to_resp2_legacy, 

70 parse_geopos_unified, 

71 parse_geosearch_generic, 

72 parse_geosearch_generic_unified, 

73 parse_hscan, 

74 parse_info, 

75 parse_lcs_idx_resp3_to_resp2_legacy, 

76 parse_lcs_idx_unified, 

77 parse_list_of_dicts, 

78 parse_list_of_dicts_resp3, 

79 parse_memory_stats, 

80 parse_memory_stats_resp3, 

81 parse_memory_stats_unified, 

82 parse_pubsub_numsub, 

83 parse_scan, 

84 parse_sentinel_get_master, 

85 parse_sentinel_master, 

86 parse_sentinel_master_resp3_to_resp2_legacy, 

87 parse_sentinel_master_unified, 

88 parse_sentinel_master_unified_resp3, 

89 parse_sentinel_masters, 

90 parse_sentinel_masters_resp3, 

91 parse_sentinel_masters_resp3_to_resp2_legacy, 

92 parse_sentinel_masters_unified, 

93 parse_sentinel_masters_unified_resp3, 

94 parse_sentinel_slaves_and_sentinels, 

95 parse_sentinel_slaves_and_sentinels_resp3, 

96 parse_sentinel_slaves_and_sentinels_resp3_to_resp2_legacy, 

97 parse_sentinel_slaves_and_sentinels_unified, 

98 parse_sentinel_slaves_and_sentinels_unified_resp3, 

99 parse_sentinel_state_resp3, 

100 parse_set_result, 

101 parse_slowlog_get, 

102 parse_stralgo, 

103 parse_stralgo_resp3_unified, 

104 parse_stralgo_unified, 

105 parse_stream_list, 

106 parse_xautoclaim, 

107 parse_xclaim, 

108 parse_xinfo_stream, 

109 parse_xpending, 

110 parse_xread, 

111 parse_xread_resp3, 

112 parse_xread_resp3_to_resp2_legacy, 

113 parse_xread_unified, 

114 parse_zadd, 

115 parse_zmscore, 

116 parse_zscan, 

117 parse_zscan_unified, 

118 sort_return_tuples, 

119 string_keys_to_dict, 

120 timestamp_to_datetime, 

121 zmpop_resp3_to_resp2_legacy, 

122 zmpop_unified, 

123 zpop_score_pairs, 

124 zpop_score_pairs_resp3_to_resp2_legacy, 

125 zpop_score_pairs_resp3_unified, 

126 zpop_score_pairs_unified, 

127 zset_score_for_rank, 

128 zset_score_for_rank_resp3, 

129 zset_score_for_rank_resp3_to_resp2_legacy, 

130 zset_score_for_rank_unified, 

131 zset_score_pairs, 

132 zset_score_pairs_resp3, 

133 zset_score_pairs_resp3_to_resp2_legacy, 

134 zset_score_pairs_resp3_to_resp2_legacy_flat, 

135 zset_score_pairs_unified, 

136) 

137 

138_RedisCallbacks = { 

139 **string_keys_to_dict( 

140 "AUTH COPY EXPIRE EXPIREAT HEXISTS HMSET MOVE MSETNX PERSIST PSETEX " 

141 "PEXPIRE PEXPIREAT RENAMENX SETEX SETNX SMOVE", 

142 bool, 

143 ), 

144 **string_keys_to_dict("HINCRBYFLOAT INCRBYFLOAT", float), 

145 **string_keys_to_dict( 

146 "ASKING FLUSHALL FLUSHDB LSET LTRIM MSET PFMERGE READONLY READWRITE " 

147 "RENAME SAVE SELECT SHUTDOWN SLAVEOF SWAPDB WATCH UNWATCH", 

148 bool_ok, 

149 ), 

150 **string_keys_to_dict("XREAD XREADGROUP", parse_xread), 

151 **string_keys_to_dict( 

152 "GEORADIUS GEORADIUSBYMEMBER GEOSEARCH", 

153 parse_geosearch_generic, 

154 ), 

155 **string_keys_to_dict("XRANGE XREVRANGE", parse_stream_list), 

156 "ACL GETUSER": parse_acl_getuser, 

157 "ACL LOAD": bool_ok, 

158 "ACL LOG": parse_acl_log, 

159 "ACL SETUSER": bool_ok, 

160 "ACL SAVE": bool_ok, 

161 "BLESS SCAN": parse_scan, 

162 "CLIENT INFO": parse_client_info, 

163 "CLIENT KILL": parse_client_kill, 

164 "CLIENT LIST": parse_client_list, 

165 "CLIENT PAUSE": bool_ok, 

166 "CLIENT SETINFO": bool_ok, 

167 "CLIENT SETNAME": bool_ok, 

168 "CLIENT UNBLOCK": bool, 

169 "CLUSTER ADDSLOTS": bool_ok, 

170 "CLUSTER ADDSLOTSRANGE": bool_ok, 

171 "CLUSTER DELSLOTS": bool_ok, 

172 "CLUSTER DELSLOTSRANGE": bool_ok, 

173 "CLUSTER FAILOVER": bool_ok, 

174 "CLUSTER FORGET": bool_ok, 

175 "CLUSTER INFO": parse_cluster_info, 

176 "CLUSTER MEET": bool_ok, 

177 "CLUSTER NODES": parse_cluster_nodes, 

178 "CLUSTER REPLICAS": parse_cluster_nodes, 

179 "CLUSTER REPLICATE": bool_ok, 

180 "CLUSTER RESET": bool_ok, 

181 "CLUSTER SAVECONFIG": bool_ok, 

182 "CLUSTER SET-CONFIG-EPOCH": bool_ok, 

183 "CLUSTER SETSLOT": bool_ok, 

184 "CLUSTER SLAVES": parse_cluster_nodes, 

185 "COMMAND": parse_command, 

186 "CONFIG RESETSTAT": bool_ok, 

187 "CONFIG SET": bool_ok, 

188 "FUNCTION DELETE": bool_ok, 

189 "FUNCTION FLUSH": bool_ok, 

190 "FUNCTION RESTORE": bool_ok, 

191 "GEODIST": float_or_none, 

192 HIMPORT_PREPARE: bool_ok, 

193 HIMPORT_SET: bool_ok, 

194 HIMPORT_DISCARD: int, 

195 HIMPORT_DISCARDALL: int, 

196 "HSCAN": parse_hscan, 

197 "INFO": parse_info, 

198 "LASTSAVE": timestamp_to_datetime, 

199 "MEMORY PURGE": bool_ok, 

200 "MODULE LOAD": bool, 

201 "MODULE UNLOAD": bool, 

202 "PING": lambda r: str_if_bytes(r) == "PONG", 

203 "PUBSUB NUMSUB": parse_pubsub_numsub, 

204 "PUBSUB SHARDNUMSUB": parse_pubsub_numsub, 

205 "QUIT": bool_ok, 

206 "SET": parse_set_result, 

207 "SCAN": parse_scan, 

208 "SCRIPT EXISTS": lambda r: list(map(bool, r)), 

209 "SCRIPT FLUSH": bool_ok, 

210 "SCRIPT KILL": bool_ok, 

211 "SCRIPT LOAD": str_if_bytes, 

212 "SENTINEL CKQUORUM": bool_ok, 

213 "SENTINEL FAILOVER": bool_ok, 

214 "SENTINEL FLUSHCONFIG": bool_ok, 

215 "SENTINEL GET-MASTER-ADDR-BY-NAME": parse_sentinel_get_master, 

216 "SENTINEL MONITOR": bool_ok, 

217 "SENTINEL RESET": bool_ok, 

218 "SENTINEL REMOVE": bool_ok, 

219 "SENTINEL SET": bool_ok, 

220 "SLOWLOG GET": parse_slowlog_get, 

221 "SLOWLOG RESET": bool_ok, 

222 "SORT": sort_return_tuples, 

223 "SSCAN": parse_scan, 

224 "TIME": lambda x: (int(x[0]), int(x[1])), 

225 "XAUTOCLAIM": parse_xautoclaim, 

226 "XCLAIM": parse_xclaim, 

227 "XGROUP CREATE": bool_ok, 

228 "XGROUP DESTROY": bool, 

229 "XGROUP SETID": bool_ok, 

230 "ARINFO": parse_arinfo, 

231 "XINFO STREAM": parse_xinfo_stream, 

232 "XPENDING": parse_xpending, 

233 "ZSCAN": parse_zscan, 

234} 

235 

236 

237_RedisCallbacksRESP2 = { 

238 **string_keys_to_dict( 

239 "SDIFF SINTER SMEMBERS SUNION", lambda r: r and set(r) or set() 

240 ), 

241 **string_keys_to_dict( 

242 "ZINTER ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION", 

243 zset_score_pairs, 

244 ), 

245 **string_keys_to_dict("ZPOPMAX ZPOPMIN", zpop_score_pairs), 

246 **string_keys_to_dict( 

247 "ZREVRANK ZRANK", 

248 zset_score_for_rank, 

249 ), 

250 **string_keys_to_dict("ZINCRBY ZSCORE", float_or_none), 

251 **string_keys_to_dict("BGREWRITEAOF BGSAVE", lambda r: True), 

252 **string_keys_to_dict("BLPOP BRPOP", lambda r: r and tuple(r) or None), 

253 **string_keys_to_dict( 

254 "BZPOPMAX BZPOPMIN", lambda r: r and (r[0], r[1], float(r[2])) or None 

255 ), 

256 "ACL CAT": lambda r: list(map(str_if_bytes, r)), 

257 "ACL GENPASS": str_if_bytes, 

258 "ACL HELP": lambda r: list(map(str_if_bytes, r)), 

259 "ACL LIST": lambda r: list(map(str_if_bytes, r)), 

260 "ACL USERS": lambda r: list(map(str_if_bytes, r)), 

261 "ACL WHOAMI": str_if_bytes, 

262 "CLIENT GETNAME": str_if_bytes, 

263 "CLIENT TRACKINGINFO": lambda r: list(map(str_if_bytes, r)), 

264 "CLUSTER GETKEYSINSLOT": lambda r: list(map(str_if_bytes, r)), 

265 "COMMAND GETKEYS": lambda r: list(map(str_if_bytes, r)), 

266 "CONFIG GET": parse_config_get, 

267 "DEBUG OBJECT": parse_debug_object, 

268 "GEOHASH": lambda r: list(map(str_if_bytes, r)), 

269 "GEOPOS": lambda r: list( 

270 map(lambda ll: (float(ll[0]), float(ll[1])) if ll is not None else None, r) 

271 ), 

272 "HGETALL": lambda r: r and pairs_to_dict(r) or {}, 

273 "HOTKEYS GET": lambda r: [pairs_to_dict(m) for m in r], 

274 "MEMORY STATS": parse_memory_stats, 

275 "MODULE LIST": lambda r: [pairs_to_dict(m) for m in r], 

276 "RESET": str_if_bytes, 

277 "SENTINEL MASTER": parse_sentinel_master, 

278 "SENTINEL MASTERS": parse_sentinel_masters, 

279 "SENTINEL SENTINELS": parse_sentinel_slaves_and_sentinels, 

280 "SENTINEL SLAVES": parse_sentinel_slaves_and_sentinels, 

281 "STRALGO": parse_stralgo, 

282 "XINFO CONSUMERS": parse_list_of_dicts, 

283 "XINFO GROUPS": parse_list_of_dicts, 

284 "ZADD": parse_zadd, 

285 "ZMSCORE": parse_zmscore, 

286} 

287 

288 

289_RedisCallbacksRESP3 = { 

290 **string_keys_to_dict( 

291 "SDIFF SINTER SMEMBERS SUNION", lambda r: r and set(r) or set() 

292 ), 

293 **string_keys_to_dict( 

294 "ZRANGE ZINTER ZPOPMAX ZPOPMIN HGETALL XREADGROUP", 

295 lambda r, **kwargs: r, 

296 ), 

297 **string_keys_to_dict( 

298 "ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION", 

299 zset_score_pairs_resp3, 

300 ), 

301 **string_keys_to_dict( 

302 "ZREVRANK ZRANK", 

303 zset_score_for_rank_resp3, 

304 ), 

305 **string_keys_to_dict("XREAD XREADGROUP", parse_xread_resp3), 

306 "ACL LOG": lambda r: ( 

307 [ 

308 {str_if_bytes(key): str_if_bytes(value) for key, value in x.items()} 

309 for x in r 

310 ] 

311 if isinstance(r, list) 

312 else bool_ok(r) 

313 ), 

314 "COMMAND": parse_command_resp3, 

315 "CONFIG GET": parse_config_get_resp3_to_resp2_legacy, 

316 "MEMORY STATS": parse_memory_stats_resp3, 

317 "SENTINEL MASTER": parse_sentinel_state_resp3, 

318 "SENTINEL MASTERS": parse_sentinel_masters_resp3, 

319 "SENTINEL SENTINELS": parse_sentinel_slaves_and_sentinels_resp3, 

320 "SENTINEL SLAVES": parse_sentinel_slaves_and_sentinels_resp3, 

321 "STRALGO": lambda r, **options: ( 

322 {str_if_bytes(key): str_if_bytes(value) for key, value in r.items()} 

323 if isinstance(r, dict) 

324 else str_if_bytes(r) 

325 ), 

326 "XINFO CONSUMERS": parse_list_of_dicts_resp3, 

327 "XINFO GROUPS": parse_list_of_dicts_resp3, 

328} 

329 

330 

331# RESP2 wire, unified response shapes (``legacy_responses=False``). 

332_RedisCallbacksRESP2Unified: dict[str, Callable[..., Any]] = { 

333 **_RedisCallbacksRESP2, 

334 **string_keys_to_dict( 

335 "ZDIFF ZINTER ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION", 

336 zset_score_pairs_unified, 

337 ), 

338 **string_keys_to_dict( 

339 "ZPOPMAX ZPOPMIN", 

340 zpop_score_pairs_unified, 

341 ), 

342 **string_keys_to_dict( 

343 "ZREVRANK ZRANK", 

344 zset_score_for_rank_unified, 

345 ), 

346 **string_keys_to_dict( 

347 "BZPOPMAX BZPOPMIN", 

348 bzpop_score_unified, 

349 ), 

350 **string_keys_to_dict("XREAD XREADGROUP", parse_xread_unified), 

351 **string_keys_to_dict( 

352 "GEORADIUS GEORADIUSBYMEMBER GEOSEARCH", 

353 parse_geosearch_generic_unified, 

354 ), 

355 **string_keys_to_dict("BLPOP BRPOP", lambda r: r or None), 

356 **string_keys_to_dict("ZMPOP BZMPOP", zmpop_unified), 

357 "ZSCAN": parse_zscan_unified, 

358 "ZRANDMEMBER": zset_score_pairs_unified, 

359 "HRANDFIELD": hrandfield_unified, 

360 "ACL GETUSER": parse_acl_getuser_unified, 

361 "CLIENT TRACKINGINFO": parse_client_trackinginfo_unified, 

362 "CLUSTER GETKEYSINSLOT": lambda r, **kwargs: r, 

363 "CLUSTER LINKS": parse_cluster_links_unified, 

364 "COMMAND": parse_command_unified, 

365 "COMMAND GETKEYS": lambda r, **kwargs: r, 

366 "FUNCTION LIST": parse_function_list_unified, 

367 "GEOPOS": parse_geopos_unified, 

368 "LCS": parse_lcs_idx_unified, 

369 "MEMORY STATS": parse_memory_stats_unified, 

370 "SENTINEL MASTER": parse_sentinel_master_unified, 

371 "SENTINEL MASTERS": parse_sentinel_masters_unified, 

372 "SENTINEL SENTINELS": parse_sentinel_slaves_and_sentinels_unified, 

373 "SENTINEL SLAVES": parse_sentinel_slaves_and_sentinels_unified, 

374 "STRALGO": parse_stralgo_unified, 

375} 

376 

377 

378# RESP3 wire, unified response shapes (``legacy_responses=False``). 

379_RedisCallbacksRESP3Unified: dict[str, Callable[..., Any]] = { 

380 **_RedisCallbacksRESP3, 

381 **string_keys_to_dict( 

382 "ZDIFF ZINTER ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION", 

383 zset_score_pairs_resp3, 

384 ), 

385 **string_keys_to_dict( 

386 "ZPOPMAX ZPOPMIN", 

387 zpop_score_pairs_resp3_unified, 

388 ), 

389 **string_keys_to_dict( 

390 "BZPOPMAX BZPOPMIN", 

391 bzpop_score_unified, 

392 ), 

393 **string_keys_to_dict("XREAD XREADGROUP", parse_xread_unified), 

394 **string_keys_to_dict( 

395 "GEORADIUS GEORADIUSBYMEMBER GEOSEARCH", 

396 parse_geosearch_generic_unified, 

397 ), 

398 "ZSCAN": parse_zscan_unified, 

399 "ZRANDMEMBER": zset_score_pairs_resp3, 

400 "ACL CAT": lambda r: list(map(str_if_bytes, r)), 

401 "ACL GENPASS": str_if_bytes, 

402 "ACL HELP": lambda r: list(map(str_if_bytes, r)), 

403 "ACL LIST": lambda r: list(map(str_if_bytes, r)), 

404 "ACL LOG": parse_acl_log_resp3_unified, 

405 "ACL USERS": lambda r: list(map(str_if_bytes, r)), 

406 "ACL WHOAMI": str_if_bytes, 

407 "CLIENT GETNAME": str_if_bytes, 

408 "CLIENT TRACKINGINFO": parse_client_trackinginfo_unified, 

409 "CLUSTER LINKS": parse_cluster_links_unified, 

410 "COMMAND": parse_command_unified, 

411 "FUNCTION LIST": parse_function_list_unified, 

412 "GEOHASH": lambda r: list(map(str_if_bytes, r)), 

413 "LCS": parse_lcs_idx_unified, 

414 "RESET": str_if_bytes, 

415 "SENTINEL MASTER": parse_sentinel_master_unified_resp3, 

416 "SENTINEL MASTERS": parse_sentinel_masters_unified_resp3, 

417 "SENTINEL SENTINELS": parse_sentinel_slaves_and_sentinels_unified_resp3, 

418 "SENTINEL SLAVES": parse_sentinel_slaves_and_sentinels_unified_resp3, 

419 "STRALGO": parse_stralgo_resp3_unified, 

420} 

421 

422 

423# RESP3 wire converted back to the legacy RESP2 Python shapes. Only the 

424# entries needed to undo RESP3-side differences are listed; everything 

425# else falls through to ``_RedisCallbacks``. Scores are re-encoded to bytes 

426# before being passed to ``score_cast_func`` so the callable observes the 

427# same input type it would on a RESP2 connection. 

428_RedisCallbacksRESP3toRESP2Legacy: dict[str, Callable[..., Any]] = { 

429 **string_keys_to_dict( 

430 "SDIFF SINTER SMEMBERS SUNION", lambda r: r and set(r) or set() 

431 ), 

432 **string_keys_to_dict( 

433 "ZINTER ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION", 

434 zset_score_pairs_resp3_to_resp2_legacy, 

435 ), 

436 "ZDIFF": zset_score_pairs_resp3_to_resp2_legacy_flat, 

437 "ZRANDMEMBER": zset_score_pairs_resp3_to_resp2_legacy_flat, 

438 **string_keys_to_dict( 

439 "ZPOPMAX ZPOPMIN", 

440 zpop_score_pairs_resp3_to_resp2_legacy, 

441 ), 

442 **string_keys_to_dict( 

443 "BZPOPMAX BZPOPMIN", 

444 bzpop_score_resp3_to_resp2_legacy, 

445 ), 

446 **string_keys_to_dict( 

447 "ZREVRANK ZRANK", 

448 zset_score_for_rank_resp3_to_resp2_legacy, 

449 ), 

450 **string_keys_to_dict("BGREWRITEAOF BGSAVE", lambda r: True), 

451 **string_keys_to_dict("XREAD XREADGROUP", parse_xread_resp3_to_resp2_legacy), 

452 **string_keys_to_dict("BLPOP BRPOP", lambda r: r and tuple(r) or None), 

453 **string_keys_to_dict("ZMPOP BZMPOP", zmpop_resp3_to_resp2_legacy), 

454 "HRANDFIELD": hrandfield_resp3_to_resp2_legacy, 

455 "ACL CAT": lambda r: list(map(str_if_bytes, r)), 

456 "ACL GENPASS": str_if_bytes, 

457 "ACL GETUSER": parse_acl_getuser_resp3_to_resp2_legacy, 

458 "ACL HELP": lambda r: list(map(str_if_bytes, r)), 

459 "ACL LIST": lambda r: list(map(str_if_bytes, r)), 

460 "ACL LOG": parse_acl_log_resp3_to_resp2_legacy, 

461 "ACL USERS": lambda r: list(map(str_if_bytes, r)), 

462 "ACL WHOAMI": str_if_bytes, 

463 "CLIENT GETNAME": str_if_bytes, 

464 "CLIENT TRACKINGINFO": parse_client_trackinginfo_resp3_to_resp2_legacy, 

465 "CLUSTER GETKEYSINSLOT": lambda r: list(map(str_if_bytes, r)), 

466 "CLUSTER LINKS": parse_cluster_links_resp3_to_resp2_legacy, 

467 "COMMAND GETKEYS": lambda r: list(map(str_if_bytes, r)), 

468 "CONFIG GET": parse_config_get_resp3_to_resp2_legacy, 

469 "DEBUG OBJECT": parse_debug_object, 

470 "FUNCTION LIST": parse_function_list_resp3_to_resp2_legacy, 

471 "GEOHASH": lambda r: list(map(str_if_bytes, r)), 

472 "GEOPOS": parse_geopos_resp3_to_resp2_legacy, 

473 "LCS": parse_lcs_idx_resp3_to_resp2_legacy, 

474 "MEMORY STATS": parse_memory_stats_resp3, 

475 "RESET": str_if_bytes, 

476 "SENTINEL MASTER": parse_sentinel_master_resp3_to_resp2_legacy, 

477 "SENTINEL MASTERS": parse_sentinel_masters_resp3_to_resp2_legacy, 

478 "SENTINEL SENTINELS": parse_sentinel_slaves_and_sentinels_resp3_to_resp2_legacy, 

479 "SENTINEL SLAVES": parse_sentinel_slaves_and_sentinels_resp3_to_resp2_legacy, 

480 "XINFO CONSUMERS": parse_list_of_dicts_resp3, 

481 "XINFO GROUPS": parse_list_of_dicts_resp3, 

482} 

483 

484 

485def get_response_callbacks( 

486 user_protocol: Optional[int], 

487 legacy_responses: bool, 

488) -> dict[str, Callable[..., Any]]: 

489 """Return the merged callback dict for the given (protocol, legacy) 

490 combination. 

491 

492 ``user_protocol`` is the value the user supplied to the client 

493 constructor (``None`` means "not specified"). ``legacy_responses`` 

494 defaults to ``True`` and selects today's RESP2-style Python shapes 

495 even when the wire protocol is RESP3. 

496 

497 Callers wrap the returned dict in ``CaseInsensitiveDict``. 

498 """ 

499 callbacks: dict[str, Callable[..., Any]] = dict(_RedisCallbacks) 

500 if legacy_responses: 

501 if user_protocol is None: 

502 callbacks.update(_RedisCallbacksRESP3toRESP2Legacy) 

503 elif user_protocol in (3, "3"): 

504 callbacks.update(_RedisCallbacksRESP3) 

505 else: 

506 callbacks.update(_RedisCallbacksRESP2) 

507 else: 

508 if user_protocol is None or user_protocol in (3, "3"): 

509 callbacks.update(_RedisCallbacksRESP3Unified) 

510 else: 

511 callbacks.update(_RedisCallbacksRESP2Unified) 

512 return callbacks