redis 5.1.0b7__tar.gz → 5.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (154) hide show
  1. {redis-5.1.0b7/redis.egg-info → redis-5.2.0}/PKG-INFO +3 -2
  2. {redis-5.1.0b7 → redis-5.2.0}/README.md +1 -1
  3. {redis-5.1.0b7 → redis-5.2.0}/redis/_parsers/helpers.py +8 -3
  4. {redis-5.1.0b7 → redis-5.2.0}/redis/_parsers/resp3.py +23 -37
  5. {redis-5.1.0b7 → redis-5.2.0}/redis/asyncio/client.py +25 -64
  6. {redis-5.1.0b7 → redis-5.2.0}/redis/asyncio/cluster.py +30 -96
  7. {redis-5.1.0b7 → redis-5.2.0}/redis/asyncio/connection.py +9 -152
  8. {redis-5.1.0b7 → redis-5.2.0}/redis/asyncio/sentinel.py +0 -1
  9. redis-5.2.0/redis/cache.py +401 -0
  10. {redis-5.1.0b7 → redis-5.2.0}/redis/client.py +35 -54
  11. {redis-5.1.0b7 → redis-5.2.0}/redis/cluster.py +64 -78
  12. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/bf/commands.py +1 -5
  13. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/core.py +92 -128
  14. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/graph/commands.py +1 -1
  15. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/graph/query_result.py +16 -1
  16. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/search/_util.py +2 -2
  17. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/search/aggregation.py +27 -0
  18. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/search/commands.py +33 -22
  19. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/search/query.py +19 -4
  20. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/search/result.py +29 -15
  21. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/timeseries/commands.py +55 -55
  22. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/timeseries/info.py +1 -1
  23. {redis-5.1.0b7 → redis-5.2.0}/redis/connection.py +371 -162
  24. {redis-5.1.0b7 → redis-5.2.0}/redis/retry.py +21 -5
  25. {redis-5.1.0b7 → redis-5.2.0}/redis/sentinel.py +9 -2
  26. {redis-5.1.0b7 → redis-5.2.0}/redis/typing.py +2 -4
  27. {redis-5.1.0b7 → redis-5.2.0}/redis/utils.py +55 -4
  28. {redis-5.1.0b7 → redis-5.2.0/redis.egg-info}/PKG-INFO +3 -2
  29. {redis-5.1.0b7 → redis-5.2.0}/redis.egg-info/SOURCES.txt +2 -2
  30. {redis-5.1.0b7 → redis-5.2.0}/redis.egg-info/requires.txt +3 -3
  31. {redis-5.1.0b7 → redis-5.2.0}/setup.py +4 -3
  32. {redis-5.1.0b7 → redis-5.2.0}/tests/conftest.py +81 -5
  33. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/conftest.py +0 -1
  34. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_bloom.py +1 -6
  35. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_cluster.py +13 -9
  36. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_commands.py +7 -9
  37. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_connect.py +11 -23
  38. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_connection.py +56 -2
  39. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_connection_pool.py +0 -1
  40. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_cwe_404.py +1 -1
  41. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_hash.py +5 -5
  42. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_json.py +1 -1
  43. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_lock.py +4 -4
  44. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_pipeline.py +10 -0
  45. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_pubsub.py +1 -1
  46. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_search.py +145 -7
  47. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_timeseries.py +1 -1
  48. {redis-5.1.0b7 → redis-5.2.0}/tests/test_bloom.py +1 -6
  49. redis-5.2.0/tests/test_cache.py +1223 -0
  50. {redis-5.1.0b7 → redis-5.2.0}/tests/test_cluster.py +4 -7
  51. {redis-5.1.0b7 → redis-5.2.0}/tests/test_command_parser.py +0 -4
  52. {redis-5.1.0b7 → redis-5.2.0}/tests/test_commands.py +15 -28
  53. {redis-5.1.0b7 → redis-5.2.0}/tests/test_connect.py +32 -23
  54. redis-5.2.0/tests/test_connection.py +565 -0
  55. {redis-5.1.0b7 → redis-5.2.0}/tests/test_encoding.py +0 -18
  56. {redis-5.1.0b7 → redis-5.2.0}/tests/test_function.py +2 -2
  57. {redis-5.1.0b7 → redis-5.2.0}/tests/test_graph.py +9 -0
  58. {redis-5.1.0b7 → redis-5.2.0}/tests/test_hash.py +9 -9
  59. {redis-5.1.0b7 → redis-5.2.0}/tests/test_json.py +1 -2
  60. {redis-5.1.0b7 → redis-5.2.0}/tests/test_lock.py +1 -1
  61. {redis-5.1.0b7 → redis-5.2.0}/tests/test_pipeline.py +10 -0
  62. {redis-5.1.0b7 → redis-5.2.0}/tests/test_retry.py +2 -2
  63. {redis-5.1.0b7 → redis-5.2.0}/tests/test_search.py +149 -18
  64. {redis-5.1.0b7 → redis-5.2.0}/tests/test_timeseries.py +1 -1
  65. redis-5.2.0/tests/test_utils.py +27 -0
  66. redis-5.1.0b7/redis/_cache.py +0 -385
  67. redis-5.1.0b7/tests/test_asyncio/test_cache.py +0 -408
  68. redis-5.1.0b7/tests/test_cache.py +0 -587
  69. redis-5.1.0b7/tests/test_connection.py +0 -298
  70. {redis-5.1.0b7 → redis-5.2.0}/INSTALL +0 -0
  71. {redis-5.1.0b7 → redis-5.2.0}/LICENSE +0 -0
  72. {redis-5.1.0b7 → redis-5.2.0}/MANIFEST.in +0 -0
  73. {redis-5.1.0b7 → redis-5.2.0}/redis/__init__.py +0 -0
  74. {redis-5.1.0b7 → redis-5.2.0}/redis/_parsers/__init__.py +0 -0
  75. {redis-5.1.0b7 → redis-5.2.0}/redis/_parsers/base.py +0 -0
  76. {redis-5.1.0b7 → redis-5.2.0}/redis/_parsers/commands.py +0 -0
  77. {redis-5.1.0b7 → redis-5.2.0}/redis/_parsers/encoders.py +0 -0
  78. {redis-5.1.0b7 → redis-5.2.0}/redis/_parsers/hiredis.py +0 -0
  79. {redis-5.1.0b7 → redis-5.2.0}/redis/_parsers/resp2.py +0 -0
  80. {redis-5.1.0b7 → redis-5.2.0}/redis/_parsers/socket.py +0 -0
  81. {redis-5.1.0b7 → redis-5.2.0}/redis/asyncio/__init__.py +0 -0
  82. {redis-5.1.0b7 → redis-5.2.0}/redis/asyncio/lock.py +0 -0
  83. {redis-5.1.0b7 → redis-5.2.0}/redis/asyncio/retry.py +0 -0
  84. {redis-5.1.0b7 → redis-5.2.0}/redis/asyncio/utils.py +0 -0
  85. {redis-5.1.0b7 → redis-5.2.0}/redis/backoff.py +0 -0
  86. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/__init__.py +0 -0
  87. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/bf/__init__.py +0 -0
  88. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/bf/info.py +0 -0
  89. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/cluster.py +0 -0
  90. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/graph/__init__.py +0 -0
  91. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/graph/edge.py +0 -0
  92. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/graph/exceptions.py +0 -0
  93. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/graph/execution_plan.py +0 -0
  94. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/graph/node.py +0 -0
  95. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/graph/path.py +0 -0
  96. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/helpers.py +0 -0
  97. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/json/__init__.py +0 -0
  98. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/json/_util.py +0 -0
  99. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/json/commands.py +0 -0
  100. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/json/decoders.py +0 -0
  101. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/json/path.py +0 -0
  102. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/redismodules.py +0 -0
  103. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/search/__init__.py +0 -0
  104. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/search/document.py +0 -0
  105. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/search/field.py +0 -0
  106. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/search/indexDefinition.py +0 -0
  107. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/search/querystring.py +0 -0
  108. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/search/reducers.py +0 -0
  109. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/search/suggestion.py +0 -0
  110. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/sentinel.py +0 -0
  111. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/timeseries/__init__.py +0 -0
  112. {redis-5.1.0b7 → redis-5.2.0}/redis/commands/timeseries/utils.py +0 -0
  113. {redis-5.1.0b7 → redis-5.2.0}/redis/crc.py +0 -0
  114. {redis-5.1.0b7 → redis-5.2.0}/redis/credentials.py +0 -0
  115. {redis-5.1.0b7 → redis-5.2.0}/redis/exceptions.py +0 -0
  116. {redis-5.1.0b7 → redis-5.2.0}/redis/lock.py +0 -0
  117. {redis-5.1.0b7 → redis-5.2.0}/redis/ocsp.py +0 -0
  118. {redis-5.1.0b7 → redis-5.2.0}/redis.egg-info/dependency_links.txt +0 -0
  119. {redis-5.1.0b7 → redis-5.2.0}/redis.egg-info/top_level.txt +0 -0
  120. {redis-5.1.0b7 → redis-5.2.0}/setup.cfg +0 -0
  121. {redis-5.1.0b7 → redis-5.2.0}/tests/__init__.py +0 -0
  122. {redis-5.1.0b7 → redis-5.2.0}/tests/mocks.py +0 -0
  123. {redis-5.1.0b7 → redis-5.2.0}/tests/ssl_utils.py +0 -0
  124. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/__init__.py +0 -0
  125. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/compat.py +0 -0
  126. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/mocks.py +0 -0
  127. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_credentials.py +0 -0
  128. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_encoding.py +0 -0
  129. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_graph.py +0 -0
  130. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_monitor.py +0 -0
  131. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_retry.py +0 -0
  132. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_scripting.py +0 -0
  133. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_sentinel.py +0 -0
  134. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/test_sentinel_managed_connection.py +0 -0
  135. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/testdata/jsontestdata.py +0 -0
  136. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/testdata/titles.csv +0 -0
  137. {redis-5.1.0b7 → redis-5.2.0}/tests/test_asyncio/testdata/will_play_text.csv.bz2 +0 -0
  138. {redis-5.1.0b7 → redis-5.2.0}/tests/test_connection_pool.py +0 -0
  139. {redis-5.1.0b7 → redis-5.2.0}/tests/test_credentials.py +0 -0
  140. {redis-5.1.0b7 → redis-5.2.0}/tests/test_graph_utils/__init__.py +0 -0
  141. {redis-5.1.0b7 → redis-5.2.0}/tests/test_graph_utils/test_edge.py +0 -0
  142. {redis-5.1.0b7 → redis-5.2.0}/tests/test_graph_utils/test_node.py +0 -0
  143. {redis-5.1.0b7 → redis-5.2.0}/tests/test_graph_utils/test_path.py +0 -0
  144. {redis-5.1.0b7 → redis-5.2.0}/tests/test_helpers.py +0 -0
  145. {redis-5.1.0b7 → redis-5.2.0}/tests/test_monitor.py +0 -0
  146. {redis-5.1.0b7 → redis-5.2.0}/tests/test_multiprocessing.py +0 -0
  147. {redis-5.1.0b7 → redis-5.2.0}/tests/test_parsers/test_helpers.py +0 -0
  148. {redis-5.1.0b7 → redis-5.2.0}/tests/test_pubsub.py +0 -0
  149. {redis-5.1.0b7 → redis-5.2.0}/tests/test_scripting.py +0 -0
  150. {redis-5.1.0b7 → redis-5.2.0}/tests/test_sentinel.py +0 -0
  151. {redis-5.1.0b7 → redis-5.2.0}/tests/test_ssl.py +0 -0
  152. {redis-5.1.0b7 → redis-5.2.0}/tests/testdata/jsontestdata.py +0 -0
  153. {redis-5.1.0b7 → redis-5.2.0}/tests/testdata/titles.csv +0 -0
  154. {redis-5.1.0b7 → redis-5.2.0}/tests/testdata/will_play_text.csv.bz2 +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: redis
3
- Version: 5.1.0b7
3
+ Version: 5.2.0
4
4
  Summary: Python client for Redis database and key-value store
5
5
  Home-page: https://github.com/redis/redis-py
6
6
  Author: Redis Inc.
@@ -24,6 +24,7 @@ Classifier: Programming Language :: Python :: 3.8
24
24
  Classifier: Programming Language :: Python :: 3.9
25
25
  Classifier: Programming Language :: Python :: 3.10
26
26
  Classifier: Programming Language :: Python :: 3.11
27
+ Classifier: Programming Language :: Python :: 3.12
27
28
  Classifier: Programming Language :: Python :: Implementation :: CPython
28
29
  Classifier: Programming Language :: Python :: Implementation :: PyPy
29
30
  Requires-Python: >=3.8
@@ -88,7 +89,7 @@ Looking for a high-level library to handle object mapping? See [redis-om-python]
88
89
 
89
90
  ## Supported Redis Versions
90
91
 
91
- The most recent version of this library supports redis version [5.0](https://github.com/redis/redis/blob/5.0/00-RELEASENOTES), [6.0](https://github.com/redis/redis/blob/6.0/00-RELEASENOTES), [6.2](https://github.com/redis/redis/blob/6.2/00-RELEASENOTES), [7.0](https://github.com/redis/redis/blob/7.0/00-RELEASENOTES) and [7.2](https://github.com/redis/redis/blob/7.2/00-RELEASENOTES).
92
+ The most recent version of this library supports redis version [5.0](https://github.com/redis/redis/blob/5.0/00-RELEASENOTES), [6.0](https://github.com/redis/redis/blob/6.0/00-RELEASENOTES), [6.2](https://github.com/redis/redis/blob/6.2/00-RELEASENOTES), [7.0](https://github.com/redis/redis/blob/7.0/00-RELEASENOTES), [7.2](https://github.com/redis/redis/blob/7.2/00-RELEASENOTES) and [7.4](https://github.com/redis/redis/blob/7.4/00-RELEASENOTES).
92
93
 
93
94
  The table below highlights version compatibility of the most-recent library versions and redis versions.
94
95
 
@@ -54,7 +54,7 @@ Looking for a high-level library to handle object mapping? See [redis-om-python]
54
54
 
55
55
  ## Supported Redis Versions
56
56
 
57
- The most recent version of this library supports redis version [5.0](https://github.com/redis/redis/blob/5.0/00-RELEASENOTES), [6.0](https://github.com/redis/redis/blob/6.0/00-RELEASENOTES), [6.2](https://github.com/redis/redis/blob/6.2/00-RELEASENOTES), [7.0](https://github.com/redis/redis/blob/7.0/00-RELEASENOTES) and [7.2](https://github.com/redis/redis/blob/7.2/00-RELEASENOTES).
57
+ The most recent version of this library supports redis version [5.0](https://github.com/redis/redis/blob/5.0/00-RELEASENOTES), [6.0](https://github.com/redis/redis/blob/6.0/00-RELEASENOTES), [6.2](https://github.com/redis/redis/blob/6.2/00-RELEASENOTES), [7.0](https://github.com/redis/redis/blob/7.0/00-RELEASENOTES), [7.2](https://github.com/redis/redis/blob/7.2/00-RELEASENOTES) and [7.4](https://github.com/redis/redis/blob/7.4/00-RELEASENOTES).
58
58
 
59
59
  The table below highlights version compatibility of the most-recent library versions and redis versions.
60
60
 
@@ -445,9 +445,11 @@ def parse_cluster_info(response, **options):
445
445
  def _parse_node_line(line):
446
446
  line_items = line.split(" ")
447
447
  node_id, addr, flags, master_id, ping, pong, epoch, connected = line.split(" ")[:8]
448
- addr = addr.split("@")[0]
448
+ ip = addr.split("@")[0]
449
+ hostname = addr.split("@")[1].split(",")[1] if "@" in addr and "," in addr else ""
449
450
  node_dict = {
450
451
  "node_id": node_id,
452
+ "hostname": hostname,
451
453
  "flags": flags,
452
454
  "master_id": master_id,
453
455
  "last_ping_sent": ping,
@@ -460,7 +462,7 @@ def _parse_node_line(line):
460
462
  if len(line_items) >= 9:
461
463
  slots, migrations = _parse_slots(line_items[8:])
462
464
  node_dict["slots"], node_dict["migrations"] = slots, migrations
463
- return addr, node_dict
465
+ return ip, node_dict
464
466
 
465
467
 
466
468
  def _parse_slots(slot_ranges):
@@ -507,7 +509,7 @@ def parse_geosearch_generic(response, **options):
507
509
  except KeyError: # it means the command was sent via execute_command
508
510
  return response
509
511
 
510
- if type(response) != list:
512
+ if not isinstance(response, list):
511
513
  response_list = [response]
512
514
  else:
513
515
  response_list = response
@@ -830,6 +832,9 @@ _RedisCallbacksRESP2 = {
830
832
 
831
833
 
832
834
  _RedisCallbacksRESP3 = {
835
+ **string_keys_to_dict(
836
+ "SDIFF SINTER SMEMBERS SUNION", lambda r: r and set(r) or set()
837
+ ),
833
838
  **string_keys_to_dict(
834
839
  "ZRANGE ZINTER ZPOPMAX ZPOPMIN ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE "
835
840
  "ZUNION HGETALL XREADGROUP",
@@ -88,15 +88,11 @@ class _RESP3Parser(_RESPBase):
88
88
  # set response
89
89
  elif byte == b"~":
90
90
  # redis can return unhashable types (like dict) in a set,
91
- # so we need to first convert to a list, and then try to convert it to a set
91
+ # so we return sets as list, all the time, for predictability
92
92
  response = [
93
93
  self._read_response(disable_decoding=disable_decoding)
94
94
  for _ in range(int(response))
95
95
  ]
96
- try:
97
- response = set(response)
98
- except TypeError:
99
- pass
100
96
  # map response
101
97
  elif byte == b"%":
102
98
  # We cannot use a dict-comprehension to parse stream.
@@ -120,6 +116,12 @@ class _RESP3Parser(_RESPBase):
120
116
  response = self.handle_push_response(
121
117
  response, disable_decoding, push_request
122
118
  )
119
+ if not push_request:
120
+ return self._read_response(
121
+ disable_decoding=disable_decoding, push_request=push_request
122
+ )
123
+ else:
124
+ return response
123
125
  else:
124
126
  raise InvalidResponse(f"Protocol Error: {raw!r}")
125
127
 
@@ -128,19 +130,10 @@ class _RESP3Parser(_RESPBase):
128
130
  return response
129
131
 
130
132
  def handle_push_response(self, response, disable_decoding, push_request):
131
- if response[0] in _INVALIDATION_MESSAGE:
132
- if self.invalidation_push_handler_func:
133
- res = self.invalidation_push_handler_func(response)
134
- else:
135
- res = None
136
- else:
137
- res = self.pubsub_push_handler_func(response)
138
- if not push_request:
139
- return self._read_response(
140
- disable_decoding=disable_decoding, push_request=push_request
141
- )
142
- else:
143
- return res
133
+ if response[0] not in _INVALIDATION_MESSAGE:
134
+ return self.pubsub_push_handler_func(response)
135
+ if self.invalidation_push_handler_func:
136
+ return self.invalidation_push_handler_func(response)
144
137
 
145
138
  def set_pubsub_push_handler(self, pubsub_push_handler_func):
146
139
  self.pubsub_push_handler_func = pubsub_push_handler_func
@@ -155,7 +148,7 @@ class _AsyncRESP3Parser(_AsyncRESPBase):
155
148
  self.pubsub_push_handler_func = self.handle_pubsub_push_response
156
149
  self.invalidation_push_handler_func = None
157
150
 
158
- def handle_pubsub_push_response(self, response):
151
+ async def handle_pubsub_push_response(self, response):
159
152
  logger = getLogger("push_response")
160
153
  logger.info("Push response: " + str(response))
161
154
  return response
@@ -233,15 +226,11 @@ class _AsyncRESP3Parser(_AsyncRESPBase):
233
226
  # set response
234
227
  elif byte == b"~":
235
228
  # redis can return unhashable types (like dict) in a set,
236
- # so we need to first convert to a list, and then try to convert it to a set
229
+ # so we always convert to a list, to have predictable return types
237
230
  response = [
238
231
  (await self._read_response(disable_decoding=disable_decoding))
239
232
  for _ in range(int(response))
240
233
  ]
241
- try:
242
- response = set(response)
243
- except TypeError:
244
- pass
245
234
  # map response
246
235
  elif byte == b"%":
247
236
  # We cannot use a dict-comprehension to parse stream.
@@ -267,6 +256,12 @@ class _AsyncRESP3Parser(_AsyncRESPBase):
267
256
  response = await self.handle_push_response(
268
257
  response, disable_decoding, push_request
269
258
  )
259
+ if not push_request:
260
+ return await self._read_response(
261
+ disable_decoding=disable_decoding, push_request=push_request
262
+ )
263
+ else:
264
+ return response
270
265
  else:
271
266
  raise InvalidResponse(f"Protocol Error: {raw!r}")
272
267
 
@@ -275,19 +270,10 @@ class _AsyncRESP3Parser(_AsyncRESPBase):
275
270
  return response
276
271
 
277
272
  async def handle_push_response(self, response, disable_decoding, push_request):
278
- if response[0] in _INVALIDATION_MESSAGE:
279
- if self.invalidation_push_handler_func:
280
- res = self.invalidation_push_handler_func(response)
281
- else:
282
- res = None
283
- else:
284
- res = self.pubsub_push_handler_func(response)
285
- if not push_request:
286
- return await self._read_response(
287
- disable_decoding=disable_decoding, push_request=push_request
288
- )
289
- else:
290
- return res
273
+ if response[0] not in _INVALIDATION_MESSAGE:
274
+ return await self.pubsub_push_handler_func(response)
275
+ if self.invalidation_push_handler_func:
276
+ return await self.invalidation_push_handler_func(response)
291
277
 
292
278
  def set_pubsub_push_handler(self, pubsub_push_handler_func):
293
279
  self.pubsub_push_handler_func = pubsub_push_handler_func
@@ -26,12 +26,6 @@ from typing import (
26
26
  cast,
27
27
  )
28
28
 
29
- from redis._cache import (
30
- DEFAULT_ALLOW_LIST,
31
- DEFAULT_DENY_LIST,
32
- DEFAULT_EVICTION_POLICY,
33
- AbstractCache,
34
- )
35
29
  from redis._parsers.helpers import (
36
30
  _RedisCallbacks,
37
31
  _RedisCallbacksRESP2,
@@ -239,13 +233,6 @@ class Redis(
239
233
  redis_connect_func=None,
240
234
  credential_provider: Optional[CredentialProvider] = None,
241
235
  protocol: Optional[int] = 2,
242
- cache_enabled: bool = False,
243
- client_cache: Optional[AbstractCache] = None,
244
- cache_max_size: int = 100,
245
- cache_ttl: int = 0,
246
- cache_policy: str = DEFAULT_EVICTION_POLICY,
247
- cache_deny_list: List[str] = DEFAULT_DENY_LIST,
248
- cache_allow_list: List[str] = DEFAULT_ALLOW_LIST,
249
236
  ):
250
237
  """
251
238
  Initialize a new Redis client.
@@ -295,13 +282,6 @@ class Redis(
295
282
  "lib_version": lib_version,
296
283
  "redis_connect_func": redis_connect_func,
297
284
  "protocol": protocol,
298
- "cache_enabled": cache_enabled,
299
- "client_cache": client_cache,
300
- "cache_max_size": cache_max_size,
301
- "cache_ttl": cache_ttl,
302
- "cache_policy": cache_policy,
303
- "cache_deny_list": cache_deny_list,
304
- "cache_allow_list": cache_allow_list,
305
285
  }
306
286
  # based on input, setup appropriate connection args
307
287
  if unix_socket_path is not None:
@@ -579,10 +559,12 @@ class Redis(
579
559
  """
580
560
  Closes Redis client connection
581
561
 
582
- :param close_connection_pool: decides whether to close the connection pool used
583
- by this Redis client, overriding Redis.auto_close_connection_pool. By default,
584
- let Redis.auto_close_connection_pool decide whether to close the connection
585
- pool.
562
+ Args:
563
+ close_connection_pool:
564
+ decides whether to close the connection pool used by this Redis client,
565
+ overriding Redis.auto_close_connection_pool.
566
+ By default, let Redis.auto_close_connection_pool decide
567
+ whether to close the connection pool.
586
568
  """
587
569
  conn = self.connection
588
570
  if conn:
@@ -624,31 +606,22 @@ class Redis(
624
606
  async def execute_command(self, *args, **options):
625
607
  """Execute a command and return a parsed response"""
626
608
  await self.initialize()
627
- command_name = args[0]
628
- keys = options.pop("keys", None) # keys are used only for client side caching
629
609
  pool = self.connection_pool
610
+ command_name = args[0]
630
611
  conn = self.connection or await pool.get_connection(command_name, **options)
631
- response_from_cache = await conn._get_from_local_cache(args)
612
+
613
+ if self.single_connection_client:
614
+ await self._single_conn_lock.acquire()
632
615
  try:
633
- if response_from_cache is not None:
634
- return response_from_cache
635
- else:
636
- try:
637
- if self.single_connection_client:
638
- await self._single_conn_lock.acquire()
639
- response = await conn.retry.call_with_retry(
640
- lambda: self._send_command_parse_response(
641
- conn, command_name, *args, **options
642
- ),
643
- lambda error: self._disconnect_raise(conn, error),
644
- )
645
- if keys:
646
- conn._add_to_local_cache(args, response, keys)
647
- return response
648
- finally:
649
- if self.single_connection_client:
650
- self._single_conn_lock.release()
616
+ return await conn.retry.call_with_retry(
617
+ lambda: self._send_command_parse_response(
618
+ conn, command_name, *args, **options
619
+ ),
620
+ lambda error: self._disconnect_raise(conn, error),
621
+ )
651
622
  finally:
623
+ if self.single_connection_client:
624
+ self._single_conn_lock.release()
652
625
  if not self.connection:
653
626
  await pool.release(conn)
654
627
 
@@ -670,6 +643,9 @@ class Redis(
670
643
  if EMPTY_RESPONSE in options:
671
644
  options.pop(EMPTY_RESPONSE)
672
645
 
646
+ # Remove keys entry, it needs only for cache.
647
+ options.pop("keys", None)
648
+
673
649
  if command_name in self.response_callbacks:
674
650
  # Mypy bug: https://github.com/python/mypy/issues/10977
675
651
  command_name = cast(str, command_name)
@@ -677,24 +653,6 @@ class Redis(
677
653
  return await retval if inspect.isawaitable(retval) else retval
678
654
  return response
679
655
 
680
- def flush_cache(self):
681
- if self.connection:
682
- self.connection.flush_cache()
683
- else:
684
- self.connection_pool.flush_cache()
685
-
686
- def delete_command_from_cache(self, command):
687
- if self.connection:
688
- self.connection.delete_command_from_cache(command)
689
- else:
690
- self.connection_pool.delete_command_from_cache(command)
691
-
692
- def invalidate_key_from_cache(self, key):
693
- if self.connection:
694
- self.connection.invalidate_key_from_cache(key)
695
- else:
696
- self.connection_pool.invalidate_key_from_cache(key)
697
-
698
656
 
699
657
  StrictRedis = Redis
700
658
 
@@ -1331,7 +1289,6 @@ class Pipeline(Redis): # lgtm [py/init-calls-subclass]
1331
1289
  def execute_command(
1332
1290
  self, *args, **kwargs
1333
1291
  ) -> Union["Pipeline", Awaitable["Pipeline"]]:
1334
- kwargs.pop("keys", None) # the keys are used only for client side caching
1335
1292
  if (self.watching or args[0] == "WATCH") and not self.explicit_transaction:
1336
1293
  return self.immediate_execute_command(*args, **kwargs)
1337
1294
  return self.pipeline_execute_command(*args, **kwargs)
@@ -1466,6 +1423,10 @@ class Pipeline(Redis): # lgtm [py/init-calls-subclass]
1466
1423
  if not isinstance(r, Exception):
1467
1424
  args, options = cmd
1468
1425
  command_name = args[0]
1426
+
1427
+ # Remove keys entry, it needs only for cache.
1428
+ options.pop("keys", None)
1429
+
1469
1430
  if command_name in self.response_callbacks:
1470
1431
  r = self.response_callbacks[command_name](r, **options)
1471
1432
  if inspect.isawaitable(r):
@@ -19,12 +19,6 @@ from typing import (
19
19
  Union,
20
20
  )
21
21
 
22
- from redis._cache import (
23
- DEFAULT_ALLOW_LIST,
24
- DEFAULT_DENY_LIST,
25
- DEFAULT_EVICTION_POLICY,
26
- AbstractCache,
27
- )
28
22
  from redis._parsers import AsyncCommandsParser, Encoder
29
23
  from redis._parsers.helpers import (
30
24
  _RedisCallbacks,
@@ -276,13 +270,6 @@ class RedisCluster(AbstractRedis, AbstractRedisCluster, AsyncRedisClusterCommand
276
270
  ssl_ciphers: Optional[str] = None,
277
271
  protocol: Optional[int] = 2,
278
272
  address_remap: Optional[Callable[[Tuple[str, int]], Tuple[str, int]]] = None,
279
- cache_enabled: bool = False,
280
- client_cache: Optional[AbstractCache] = None,
281
- cache_max_size: int = 100,
282
- cache_ttl: int = 0,
283
- cache_policy: str = DEFAULT_EVICTION_POLICY,
284
- cache_deny_list: List[str] = DEFAULT_DENY_LIST,
285
- cache_allow_list: List[str] = DEFAULT_ALLOW_LIST,
286
273
  ) -> None:
287
274
  if db:
288
275
  raise RedisClusterException(
@@ -326,14 +313,6 @@ class RedisCluster(AbstractRedis, AbstractRedisCluster, AsyncRedisClusterCommand
326
313
  "socket_timeout": socket_timeout,
327
314
  "retry": retry,
328
315
  "protocol": protocol,
329
- # Client cache related kwargs
330
- "cache_enabled": cache_enabled,
331
- "client_cache": client_cache,
332
- "cache_max_size": cache_max_size,
333
- "cache_ttl": cache_ttl,
334
- "cache_policy": cache_policy,
335
- "cache_deny_list": cache_deny_list,
336
- "cache_allow_list": cache_allow_list,
337
316
  }
338
317
 
339
318
  if ssl:
@@ -938,18 +917,6 @@ class RedisCluster(AbstractRedis, AbstractRedisCluster, AsyncRedisClusterCommand
938
917
  thread_local=thread_local,
939
918
  )
940
919
 
941
- def flush_cache(self):
942
- if self.nodes_manager:
943
- self.nodes_manager.flush_cache()
944
-
945
- def delete_command_from_cache(self, command):
946
- if self.nodes_manager:
947
- self.nodes_manager.delete_command_from_cache(command)
948
-
949
- def invalidate_key_from_cache(self, key):
950
- if self.nodes_manager:
951
- self.nodes_manager.invalidate_key_from_cache(key)
952
-
953
920
 
954
921
  class ClusterNode:
955
922
  """
@@ -1067,6 +1034,9 @@ class ClusterNode:
1067
1034
  if EMPTY_RESPONSE in kwargs:
1068
1035
  kwargs.pop(EMPTY_RESPONSE)
1069
1036
 
1037
+ # Remove keys entry, it needs only for cache.
1038
+ kwargs.pop("keys", None)
1039
+
1070
1040
  # Return response
1071
1041
  if command in self.response_callbacks:
1072
1042
  return self.response_callbacks[command](response, **kwargs)
@@ -1076,25 +1046,16 @@ class ClusterNode:
1076
1046
  async def execute_command(self, *args: Any, **kwargs: Any) -> Any:
1077
1047
  # Acquire connection
1078
1048
  connection = self.acquire_connection()
1079
- keys = kwargs.pop("keys", None)
1080
1049
 
1081
- response_from_cache = await connection._get_from_local_cache(args)
1082
- if response_from_cache is not None:
1083
- self._free.append(connection)
1084
- return response_from_cache
1085
- else:
1086
- # Execute command
1087
- await connection.send_packed_command(connection.pack_command(*args), False)
1050
+ # Execute command
1051
+ await connection.send_packed_command(connection.pack_command(*args), False)
1088
1052
 
1089
- # Read response
1090
- try:
1091
- response = await self.parse_response(connection, args[0], **kwargs)
1092
- if keys:
1093
- connection._add_to_local_cache(args, response, keys)
1094
- return response
1095
- finally:
1096
- # Release connection
1097
- self._free.append(connection)
1053
+ # Read response
1054
+ try:
1055
+ return await self.parse_response(connection, args[0], **kwargs)
1056
+ finally:
1057
+ # Release connection
1058
+ self._free.append(connection)
1098
1059
 
1099
1060
  async def execute_pipeline(self, commands: List["PipelineCommand"]) -> bool:
1100
1061
  # Acquire connection
@@ -1121,18 +1082,6 @@ class ClusterNode:
1121
1082
 
1122
1083
  return ret
1123
1084
 
1124
- def flush_cache(self):
1125
- for connection in self._connections:
1126
- connection.flush_cache()
1127
-
1128
- def delete_command_from_cache(self, command):
1129
- for connection in self._connections:
1130
- connection.delete_command_from_cache(command)
1131
-
1132
- def invalidate_key_from_cache(self, key):
1133
- for connection in self._connections:
1134
- connection.invalidate_key_from_cache(key)
1135
-
1136
1085
 
1137
1086
  class NodesManager:
1138
1087
  __slots__ = (
@@ -1317,6 +1266,8 @@ class NodesManager:
1317
1266
  port = int(primary_node[1])
1318
1267
  host, port = self.remap_host_port(host, port)
1319
1268
 
1269
+ nodes_for_slot = []
1270
+
1320
1271
  target_node = tmp_nodes_cache.get(get_node_name(host, port))
1321
1272
  if not target_node:
1322
1273
  target_node = ClusterNode(
@@ -1324,30 +1275,26 @@ class NodesManager:
1324
1275
  )
1325
1276
  # add this node to the nodes cache
1326
1277
  tmp_nodes_cache[target_node.name] = target_node
1278
+ nodes_for_slot.append(target_node)
1279
+
1280
+ replica_nodes = slot[3:]
1281
+ for replica_node in replica_nodes:
1282
+ host = replica_node[0]
1283
+ port = replica_node[1]
1284
+ host, port = self.remap_host_port(host, port)
1285
+
1286
+ target_replica_node = tmp_nodes_cache.get(get_node_name(host, port))
1287
+ if not target_replica_node:
1288
+ target_replica_node = ClusterNode(
1289
+ host, port, REPLICA, **self.connection_kwargs
1290
+ )
1291
+ # add this node to the nodes cache
1292
+ tmp_nodes_cache[target_replica_node.name] = target_replica_node
1293
+ nodes_for_slot.append(target_replica_node)
1327
1294
 
1328
1295
  for i in range(int(slot[0]), int(slot[1]) + 1):
1329
1296
  if i not in tmp_slots:
1330
- tmp_slots[i] = []
1331
- tmp_slots[i].append(target_node)
1332
- replica_nodes = [slot[j] for j in range(3, len(slot))]
1333
-
1334
- for replica_node in replica_nodes:
1335
- host = replica_node[0]
1336
- port = replica_node[1]
1337
- host, port = self.remap_host_port(host, port)
1338
-
1339
- target_replica_node = tmp_nodes_cache.get(
1340
- get_node_name(host, port)
1341
- )
1342
- if not target_replica_node:
1343
- target_replica_node = ClusterNode(
1344
- host, port, REPLICA, **self.connection_kwargs
1345
- )
1346
- tmp_slots[i].append(target_replica_node)
1347
- # add this node to the nodes cache
1348
- tmp_nodes_cache[target_replica_node.name] = (
1349
- target_replica_node
1350
- )
1297
+ tmp_slots[i] = nodes_for_slot
1351
1298
  else:
1352
1299
  # Validate that 2 nodes want to use the same slot cache
1353
1300
  # setup
@@ -1418,18 +1365,6 @@ class NodesManager:
1418
1365
  return self.address_remap((host, port))
1419
1366
  return host, port
1420
1367
 
1421
- def flush_cache(self):
1422
- for node in self.nodes_cache.values():
1423
- node.flush_cache()
1424
-
1425
- def delete_command_from_cache(self, command):
1426
- for node in self.nodes_cache.values():
1427
- node.delete_command_from_cache(command)
1428
-
1429
- def invalidate_key_from_cache(self, key):
1430
- for node in self.nodes_cache.values():
1431
- node.invalidate_key_from_cache(key)
1432
-
1433
1368
 
1434
1369
  class ClusterPipeline(AbstractRedis, AbstractRedisCluster, AsyncRedisClusterCommands):
1435
1370
  """
@@ -1518,7 +1453,6 @@ class ClusterPipeline(AbstractRedis, AbstractRedisCluster, AsyncRedisClusterComm
1518
1453
  or List[:class:`~.ClusterNode`] or Dict[Any, :class:`~.ClusterNode`]
1519
1454
  - Rest of the kwargs are passed to the Redis connection
1520
1455
  """
1521
- kwargs.pop("keys", None) # the keys are used only for client side caching
1522
1456
  self._command_stack.append(
1523
1457
  PipelineCommand(len(self._command_stack), *args, **kwargs)
1524
1458
  )