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 "CLIENT INFO": parse_client_info, 

162 "CLIENT KILL": parse_client_kill, 

163 "CLIENT LIST": parse_client_list, 

164 "CLIENT PAUSE": bool_ok, 

165 "CLIENT SETINFO": bool_ok, 

166 "CLIENT SETNAME": bool_ok, 

167 "CLIENT UNBLOCK": bool, 

168 "CLUSTER ADDSLOTS": bool_ok, 

169 "CLUSTER ADDSLOTSRANGE": bool_ok, 

170 "CLUSTER DELSLOTS": bool_ok, 

171 "CLUSTER DELSLOTSRANGE": bool_ok, 

172 "CLUSTER FAILOVER": bool_ok, 

173 "CLUSTER FORGET": bool_ok, 

174 "CLUSTER INFO": parse_cluster_info, 

175 "CLUSTER MEET": bool_ok, 

176 "CLUSTER NODES": parse_cluster_nodes, 

177 "CLUSTER REPLICAS": parse_cluster_nodes, 

178 "CLUSTER REPLICATE": bool_ok, 

179 "CLUSTER RESET": bool_ok, 

180 "CLUSTER SAVECONFIG": bool_ok, 

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

182 "CLUSTER SETSLOT": bool_ok, 

183 "CLUSTER SLAVES": parse_cluster_nodes, 

184 "COMMAND": parse_command, 

185 "CONFIG RESETSTAT": bool_ok, 

186 "CONFIG SET": bool_ok, 

187 "FUNCTION DELETE": bool_ok, 

188 "FUNCTION FLUSH": bool_ok, 

189 "FUNCTION RESTORE": bool_ok, 

190 "GEODIST": float_or_none, 

191 HIMPORT_PREPARE: bool_ok, 

192 HIMPORT_SET: bool_ok, 

193 HIMPORT_DISCARD: int, 

194 HIMPORT_DISCARDALL: int, 

195 "HSCAN": parse_hscan, 

196 "INFO": parse_info, 

197 "LASTSAVE": timestamp_to_datetime, 

198 "MEMORY PURGE": bool_ok, 

199 "MODULE LOAD": bool, 

200 "MODULE UNLOAD": bool, 

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

202 "PUBSUB NUMSUB": parse_pubsub_numsub, 

203 "PUBSUB SHARDNUMSUB": parse_pubsub_numsub, 

204 "QUIT": bool_ok, 

205 "SET": parse_set_result, 

206 "SCAN": parse_scan, 

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

208 "SCRIPT FLUSH": bool_ok, 

209 "SCRIPT KILL": bool_ok, 

210 "SCRIPT LOAD": str_if_bytes, 

211 "SENTINEL CKQUORUM": bool_ok, 

212 "SENTINEL FAILOVER": bool_ok, 

213 "SENTINEL FLUSHCONFIG": bool_ok, 

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

215 "SENTINEL MONITOR": bool_ok, 

216 "SENTINEL RESET": bool_ok, 

217 "SENTINEL REMOVE": bool_ok, 

218 "SENTINEL SET": bool_ok, 

219 "SLOWLOG GET": parse_slowlog_get, 

220 "SLOWLOG RESET": bool_ok, 

221 "SORT": sort_return_tuples, 

222 "SSCAN": parse_scan, 

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

224 "XAUTOCLAIM": parse_xautoclaim, 

225 "XCLAIM": parse_xclaim, 

226 "XGROUP CREATE": bool_ok, 

227 "XGROUP DESTROY": bool, 

228 "XGROUP SETID": bool_ok, 

229 "ARINFO": parse_arinfo, 

230 "XINFO STREAM": parse_xinfo_stream, 

231 "XPENDING": parse_xpending, 

232 "ZSCAN": parse_zscan, 

233} 

234 

235 

236_RedisCallbacksRESP2 = { 

237 **string_keys_to_dict( 

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

239 ), 

240 **string_keys_to_dict( 

241 "ZINTER ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION", 

242 zset_score_pairs, 

243 ), 

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

245 **string_keys_to_dict( 

246 "ZREVRANK ZRANK", 

247 zset_score_for_rank, 

248 ), 

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

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

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

252 **string_keys_to_dict( 

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

254 ), 

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

256 "ACL GENPASS": str_if_bytes, 

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

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

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

260 "ACL WHOAMI": str_if_bytes, 

261 "CLIENT GETNAME": str_if_bytes, 

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

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

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

265 "CONFIG GET": parse_config_get, 

266 "DEBUG OBJECT": parse_debug_object, 

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

268 "GEOPOS": lambda r: list( 

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

270 ), 

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

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

273 "MEMORY STATS": parse_memory_stats, 

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

275 "RESET": str_if_bytes, 

276 "SENTINEL MASTER": parse_sentinel_master, 

277 "SENTINEL MASTERS": parse_sentinel_masters, 

278 "SENTINEL SENTINELS": parse_sentinel_slaves_and_sentinels, 

279 "SENTINEL SLAVES": parse_sentinel_slaves_and_sentinels, 

280 "STRALGO": parse_stralgo, 

281 "XINFO CONSUMERS": parse_list_of_dicts, 

282 "XINFO GROUPS": parse_list_of_dicts, 

283 "ZADD": parse_zadd, 

284 "ZMSCORE": parse_zmscore, 

285} 

286 

287 

288_RedisCallbacksRESP3 = { 

289 **string_keys_to_dict( 

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

291 ), 

292 **string_keys_to_dict( 

293 "ZRANGE ZINTER ZPOPMAX ZPOPMIN HGETALL XREADGROUP", 

294 lambda r, **kwargs: r, 

295 ), 

296 **string_keys_to_dict( 

297 "ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION", 

298 zset_score_pairs_resp3, 

299 ), 

300 **string_keys_to_dict( 

301 "ZREVRANK ZRANK", 

302 zset_score_for_rank_resp3, 

303 ), 

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

305 "ACL LOG": lambda r: ( 

306 [ 

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

308 for x in r 

309 ] 

310 if isinstance(r, list) 

311 else bool_ok(r) 

312 ), 

313 "COMMAND": parse_command_resp3, 

314 "CONFIG GET": parse_config_get_resp3_to_resp2_legacy, 

315 "MEMORY STATS": parse_memory_stats_resp3, 

316 "SENTINEL MASTER": parse_sentinel_state_resp3, 

317 "SENTINEL MASTERS": parse_sentinel_masters_resp3, 

318 "SENTINEL SENTINELS": parse_sentinel_slaves_and_sentinels_resp3, 

319 "SENTINEL SLAVES": parse_sentinel_slaves_and_sentinels_resp3, 

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

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

322 if isinstance(r, dict) 

323 else str_if_bytes(r) 

324 ), 

325 "XINFO CONSUMERS": parse_list_of_dicts_resp3, 

326 "XINFO GROUPS": parse_list_of_dicts_resp3, 

327} 

328 

329 

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

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

332 **_RedisCallbacksRESP2, 

333 **string_keys_to_dict( 

334 "ZDIFF ZINTER ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION", 

335 zset_score_pairs_unified, 

336 ), 

337 **string_keys_to_dict( 

338 "ZPOPMAX ZPOPMIN", 

339 zpop_score_pairs_unified, 

340 ), 

341 **string_keys_to_dict( 

342 "ZREVRANK ZRANK", 

343 zset_score_for_rank_unified, 

344 ), 

345 **string_keys_to_dict( 

346 "BZPOPMAX BZPOPMIN", 

347 bzpop_score_unified, 

348 ), 

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

350 **string_keys_to_dict( 

351 "GEORADIUS GEORADIUSBYMEMBER GEOSEARCH", 

352 parse_geosearch_generic_unified, 

353 ), 

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

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

356 "ZSCAN": parse_zscan_unified, 

357 "ZRANDMEMBER": zset_score_pairs_unified, 

358 "HRANDFIELD": hrandfield_unified, 

359 "ACL GETUSER": parse_acl_getuser_unified, 

360 "CLIENT TRACKINGINFO": parse_client_trackinginfo_unified, 

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

362 "CLUSTER LINKS": parse_cluster_links_unified, 

363 "COMMAND": parse_command_unified, 

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

365 "FUNCTION LIST": parse_function_list_unified, 

366 "GEOPOS": parse_geopos_unified, 

367 "LCS": parse_lcs_idx_unified, 

368 "MEMORY STATS": parse_memory_stats_unified, 

369 "SENTINEL MASTER": parse_sentinel_master_unified, 

370 "SENTINEL MASTERS": parse_sentinel_masters_unified, 

371 "SENTINEL SENTINELS": parse_sentinel_slaves_and_sentinels_unified, 

372 "SENTINEL SLAVES": parse_sentinel_slaves_and_sentinels_unified, 

373 "STRALGO": parse_stralgo_unified, 

374} 

375 

376 

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

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

379 **_RedisCallbacksRESP3, 

380 **string_keys_to_dict( 

381 "ZDIFF ZINTER ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION", 

382 zset_score_pairs_resp3, 

383 ), 

384 **string_keys_to_dict( 

385 "ZPOPMAX ZPOPMIN", 

386 zpop_score_pairs_resp3_unified, 

387 ), 

388 **string_keys_to_dict( 

389 "BZPOPMAX BZPOPMIN", 

390 bzpop_score_unified, 

391 ), 

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

393 **string_keys_to_dict( 

394 "GEORADIUS GEORADIUSBYMEMBER GEOSEARCH", 

395 parse_geosearch_generic_unified, 

396 ), 

397 "ZSCAN": parse_zscan_unified, 

398 "ZRANDMEMBER": zset_score_pairs_resp3, 

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

400 "ACL GENPASS": str_if_bytes, 

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

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

403 "ACL LOG": parse_acl_log_resp3_unified, 

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

405 "ACL WHOAMI": str_if_bytes, 

406 "CLIENT GETNAME": str_if_bytes, 

407 "CLIENT TRACKINGINFO": parse_client_trackinginfo_unified, 

408 "CLUSTER LINKS": parse_cluster_links_unified, 

409 "COMMAND": parse_command_unified, 

410 "FUNCTION LIST": parse_function_list_unified, 

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

412 "LCS": parse_lcs_idx_unified, 

413 "RESET": str_if_bytes, 

414 "SENTINEL MASTER": parse_sentinel_master_unified_resp3, 

415 "SENTINEL MASTERS": parse_sentinel_masters_unified_resp3, 

416 "SENTINEL SENTINELS": parse_sentinel_slaves_and_sentinels_unified_resp3, 

417 "SENTINEL SLAVES": parse_sentinel_slaves_and_sentinels_unified_resp3, 

418 "STRALGO": parse_stralgo_resp3_unified, 

419} 

420 

421 

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

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

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

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

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

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

428 **string_keys_to_dict( 

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

430 ), 

431 **string_keys_to_dict( 

432 "ZINTER ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION", 

433 zset_score_pairs_resp3_to_resp2_legacy, 

434 ), 

435 "ZDIFF": zset_score_pairs_resp3_to_resp2_legacy_flat, 

436 "ZRANDMEMBER": zset_score_pairs_resp3_to_resp2_legacy_flat, 

437 **string_keys_to_dict( 

438 "ZPOPMAX ZPOPMIN", 

439 zpop_score_pairs_resp3_to_resp2_legacy, 

440 ), 

441 **string_keys_to_dict( 

442 "BZPOPMAX BZPOPMIN", 

443 bzpop_score_resp3_to_resp2_legacy, 

444 ), 

445 **string_keys_to_dict( 

446 "ZREVRANK ZRANK", 

447 zset_score_for_rank_resp3_to_resp2_legacy, 

448 ), 

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

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

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

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

453 "HRANDFIELD": hrandfield_resp3_to_resp2_legacy, 

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

455 "ACL GENPASS": str_if_bytes, 

456 "ACL GETUSER": parse_acl_getuser_resp3_to_resp2_legacy, 

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

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

459 "ACL LOG": parse_acl_log_resp3_to_resp2_legacy, 

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

461 "ACL WHOAMI": str_if_bytes, 

462 "CLIENT GETNAME": str_if_bytes, 

463 "CLIENT TRACKINGINFO": parse_client_trackinginfo_resp3_to_resp2_legacy, 

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

465 "CLUSTER LINKS": parse_cluster_links_resp3_to_resp2_legacy, 

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

467 "CONFIG GET": parse_config_get_resp3_to_resp2_legacy, 

468 "DEBUG OBJECT": parse_debug_object, 

469 "FUNCTION LIST": parse_function_list_resp3_to_resp2_legacy, 

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

471 "GEOPOS": parse_geopos_resp3_to_resp2_legacy, 

472 "LCS": parse_lcs_idx_resp3_to_resp2_legacy, 

473 "MEMORY STATS": parse_memory_stats_resp3, 

474 "RESET": str_if_bytes, 

475 "SENTINEL MASTER": parse_sentinel_master_resp3_to_resp2_legacy, 

476 "SENTINEL MASTERS": parse_sentinel_masters_resp3_to_resp2_legacy, 

477 "SENTINEL SENTINELS": parse_sentinel_slaves_and_sentinels_resp3_to_resp2_legacy, 

478 "SENTINEL SLAVES": parse_sentinel_slaves_and_sentinels_resp3_to_resp2_legacy, 

479 "XINFO CONSUMERS": parse_list_of_dicts_resp3, 

480 "XINFO GROUPS": parse_list_of_dicts_resp3, 

481} 

482 

483 

484def get_response_callbacks( 

485 user_protocol: Optional[int], 

486 legacy_responses: bool, 

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

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

489 combination. 

490 

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

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

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

494 even when the wire protocol is RESP3. 

495 

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

497 """ 

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

499 if legacy_responses: 

500 if user_protocol is None: 

501 callbacks.update(_RedisCallbacksRESP3toRESP2Legacy) 

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

503 callbacks.update(_RedisCallbacksRESP3) 

504 else: 

505 callbacks.update(_RedisCallbacksRESP2) 

506 else: 

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

508 callbacks.update(_RedisCallbacksRESP3Unified) 

509 else: 

510 callbacks.update(_RedisCallbacksRESP2Unified) 

511 return callbacks