redis 7.0.0b2__tar.gz → 7.0.0b3__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.
- {redis-7.0.0b2 → redis-7.0.0b3}/PKG-INFO +3 -1
- {redis-7.0.0b2 → redis-7.0.0b3}/dev_requirements.txt +1 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/pyproject.toml +9 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/__init__.py +1 -1
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/asyncio/client.py +14 -5
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/asyncio/cluster.py +5 -1
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/asyncio/connection.py +18 -0
- redis-7.0.0b3/redis/asyncio/http/http_client.py +265 -0
- redis-7.0.0b3/redis/asyncio/multidb/client.py +528 -0
- redis-7.0.0b3/redis/asyncio/multidb/command_executor.py +339 -0
- redis-7.0.0b3/redis/asyncio/multidb/config.py +210 -0
- redis-7.0.0b3/redis/asyncio/multidb/database.py +69 -0
- redis-7.0.0b3/redis/asyncio/multidb/event.py +84 -0
- redis-7.0.0b3/redis/asyncio/multidb/failover.py +125 -0
- redis-7.0.0b3/redis/asyncio/multidb/failure_detector.py +38 -0
- redis-7.0.0b3/redis/asyncio/multidb/healthcheck.py +292 -0
- redis-7.0.0b3/redis/background.py +204 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/client.py +22 -3
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/cluster.py +3 -1
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/core.py +10 -3
- redis-7.0.0b3/redis/data_structure.py +81 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/event.py +84 -10
- redis-7.0.0b3/redis/http/http_client.py +425 -0
- redis-7.0.0b3/redis/multidb/circuit.py +144 -0
- redis-7.0.0b3/redis/multidb/client.py +524 -0
- redis-7.0.0b3/redis/multidb/command_executor.py +350 -0
- redis-7.0.0b3/redis/multidb/config.py +207 -0
- redis-7.0.0b3/redis/multidb/database.py +130 -0
- redis-7.0.0b3/redis/multidb/event.py +89 -0
- redis-7.0.0b3/redis/multidb/exception.py +17 -0
- redis-7.0.0b3/redis/multidb/failover.py +125 -0
- redis-7.0.0b3/redis/multidb/failure_detector.py +104 -0
- redis-7.0.0b3/redis/multidb/healthcheck.py +289 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/retry.py +14 -1
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/utils.py +14 -0
- redis-7.0.0b3/tests/__init__.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/conftest.py +7 -0
- redis-7.0.0b3/tests/test_asyncio/__init__.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_commands.py +23 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_connection_pool.py +3 -0
- redis-7.0.0b3/tests/test_asyncio/test_multidb/__init__.py +0 -0
- redis-7.0.0b3/tests/test_asyncio/test_multidb/conftest.py +131 -0
- redis-7.0.0b3/tests/test_asyncio/test_multidb/test_client.py +628 -0
- redis-7.0.0b3/tests/test_asyncio/test_multidb/test_command_executor.py +181 -0
- redis-7.0.0b3/tests/test_asyncio/test_multidb/test_config.py +166 -0
- redis-7.0.0b3/tests/test_asyncio/test_multidb/test_failover.py +169 -0
- redis-7.0.0b3/tests/test_asyncio/test_multidb/test_failure_detector.py +128 -0
- redis-7.0.0b3/tests/test_asyncio/test_multidb/test_healthcheck.py +401 -0
- redis-7.0.0b3/tests/test_asyncio/test_multidb/test_pipeline.py +488 -0
- redis-7.0.0b3/tests/test_asyncio/test_scenario/__init__.py +0 -0
- redis-7.0.0b3/tests/test_asyncio/test_scenario/conftest.py +116 -0
- redis-7.0.0b3/tests/test_asyncio/test_scenario/test_active_active.py +420 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_vsets.py +2 -2
- redis-7.0.0b3/tests/test_auth/__init__.py +0 -0
- redis-7.0.0b3/tests/test_background.py +94 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_commands.py +51 -0
- redis-7.0.0b3/tests/test_data_structure.py +94 -0
- redis-7.0.0b3/tests/test_event.py +67 -0
- redis-7.0.0b3/tests/test_http/__init__.py +0 -0
- redis-7.0.0b3/tests/test_http/test_http_client.py +371 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_maint_notifications_handling.py +3 -0
- redis-7.0.0b3/tests/test_multidb/__init__.py +0 -0
- redis-7.0.0b3/tests/test_multidb/conftest.py +131 -0
- redis-7.0.0b3/tests/test_multidb/test_circuit.py +57 -0
- redis-7.0.0b3/tests/test_multidb/test_client.py +615 -0
- redis-7.0.0b3/tests/test_multidb/test_command_executor.py +173 -0
- redis-7.0.0b3/tests/test_multidb/test_config.py +161 -0
- redis-7.0.0b3/tests/test_multidb/test_failover.py +161 -0
- redis-7.0.0b3/tests/test_multidb/test_failure_detector.py +117 -0
- redis-7.0.0b3/tests/test_multidb/test_healthcheck.py +385 -0
- redis-7.0.0b3/tests/test_multidb/test_pipeline.py +489 -0
- redis-7.0.0b3/tests/test_scenario/__init__.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_scenario/conftest.py +119 -3
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_scenario/maint_notifications_helpers.py +29 -14
- redis-7.0.0b3/tests/test_scenario/test_active_active.py +460 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_scenario/test_maint_notifications.py +9 -24
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_vsets.py +2 -2
- {redis-7.0.0b2 → redis-7.0.0b3}/.gitignore +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/LICENSE +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/README.md +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/_parsers/__init__.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/_parsers/base.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/_parsers/commands.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/_parsers/encoders.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/_parsers/helpers.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/_parsers/hiredis.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/_parsers/resp2.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/_parsers/resp3.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/_parsers/socket.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/asyncio/__init__.py +0 -0
- {redis-7.0.0b2/redis/auth → redis-7.0.0b3/redis/asyncio/http}/__init__.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/asyncio/lock.py +0 -0
- {redis-7.0.0b2/tests → redis-7.0.0b3/redis/asyncio/multidb}/__init__.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/asyncio/retry.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/asyncio/sentinel.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/asyncio/utils.py +0 -0
- {redis-7.0.0b2/tests/test_asyncio → redis-7.0.0b3/redis/auth}/__init__.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/auth/err.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/auth/idp.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/auth/token.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/auth/token_manager.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/backoff.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/cache.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/__init__.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/bf/__init__.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/bf/commands.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/bf/info.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/cluster.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/helpers.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/json/__init__.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/json/_util.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/json/commands.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/json/decoders.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/json/path.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/redismodules.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/search/__init__.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/search/_util.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/search/aggregation.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/search/commands.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/search/dialect.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/search/document.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/search/field.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/search/index_definition.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/search/profile_information.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/search/query.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/search/querystring.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/search/reducers.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/search/result.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/search/suggestion.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/sentinel.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/timeseries/__init__.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/timeseries/commands.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/timeseries/info.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/timeseries/utils.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/vectorset/__init__.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/vectorset/commands.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/commands/vectorset/utils.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/connection.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/crc.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/credentials.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/exceptions.py +0 -0
- {redis-7.0.0b2/tests/test_auth → redis-7.0.0b3/redis/http}/__init__.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/lock.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/maint_notifications.py +0 -0
- {redis-7.0.0b2/tests/test_scenario → redis-7.0.0b3/redis/multidb}/__init__.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/ocsp.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/py.typed +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/sentinel.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/redis/typing.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/entraid_utils.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/mocks.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/ssl_utils.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/compat.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/conftest.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/mocks.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_bloom.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_cluster.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_cluster_transaction.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_connect.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_connection.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_credentials.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_cwe_404.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_encoding.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_hash.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_json.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_lock.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_monitor.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_pipeline.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_pubsub.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_retry.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_scripting.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_search.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_sentinel.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_sentinel_managed_connection.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_ssl.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_timeseries.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_usage_counter.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/test_utils.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/testdata/jsontestdata.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/testdata/titles.csv +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_asyncio/testdata/will_play_text.csv.bz2 +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_auth/test_token.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_auth/test_token_manager.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_backoff.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_bloom.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_cache.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_cluster.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_cluster_transaction.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_command_parser.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_connect.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_connection.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_connection_pool.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_credentials.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_encoding.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_function.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_hash.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_helpers.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_json.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_lock.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_maint_notifications.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_max_connections_error.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_monitor.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_multiprocessing.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_parsers/test_helpers.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_pipeline.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_pubsub.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_retry.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_scenario/fault_injector_client.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_scripting.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_search.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_sentinel.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_sentinel_managed_connection.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_ssl.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_timeseries.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/test_utils.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/testdata/jsontestdata.py +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/testdata/titles.csv +0 -0
- {redis-7.0.0b2 → redis-7.0.0b3}/tests/testdata/will_play_text.csv.bz2 +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: redis
|
|
3
|
-
Version: 7.0.
|
|
3
|
+
Version: 7.0.0b3
|
|
4
4
|
Summary: Python client for Redis database and key-value store
|
|
5
5
|
Project-URL: Changes, https://github.com/redis/redis-py/releases
|
|
6
6
|
Project-URL: Code, https://github.com/redis/redis-py
|
|
@@ -28,6 +28,8 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
|
28
28
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
29
29
|
Requires-Python: >=3.9
|
|
30
30
|
Requires-Dist: async-timeout>=4.0.3; python_full_version < '3.11.3'
|
|
31
|
+
Provides-Extra: circuit-breaker
|
|
32
|
+
Requires-Dist: pybreaker>=1.4.0; extra == 'circuit-breaker'
|
|
31
33
|
Provides-Extra: hiredis
|
|
32
34
|
Requires-Dist: hiredis>=3.2.0; extra == 'hiredis'
|
|
33
35
|
Provides-Extra: jwt
|
|
@@ -42,6 +42,9 @@ ocsp = [
|
|
|
42
42
|
jwt = [
|
|
43
43
|
"PyJWT>=2.9.0",
|
|
44
44
|
]
|
|
45
|
+
circuit_breaker = [
|
|
46
|
+
"pybreaker>=1.4.0"
|
|
47
|
+
]
|
|
45
48
|
|
|
46
49
|
[project.urls]
|
|
47
50
|
Changes = "https://github.com/redis/redis-py/releases"
|
|
@@ -80,6 +83,12 @@ filterwarnings = [
|
|
|
80
83
|
# Ignore a coverage warning when COVERAGE_CORE=sysmon for Pythons < 3.12.
|
|
81
84
|
"ignore:sys.monitoring isn't available:coverage.exceptions.CoverageWarning",
|
|
82
85
|
]
|
|
86
|
+
log_cli_level = "INFO"
|
|
87
|
+
log_cli_date_format = "%H:%M:%S:%f"
|
|
88
|
+
log_cli = false
|
|
89
|
+
log_cli_format = "%(asctime)s %(levelname)s %(threadName)s: %(message)s"
|
|
90
|
+
log_level = "INFO"
|
|
91
|
+
capture = "yes"
|
|
83
92
|
|
|
84
93
|
[tool.ruff]
|
|
85
94
|
target-version = "py39"
|
|
@@ -1161,9 +1161,12 @@ class PubSub:
|
|
|
1161
1161
|
return await self.handle_message(response, ignore_subscribe_messages)
|
|
1162
1162
|
return None
|
|
1163
1163
|
|
|
1164
|
-
def ping(self, message=None) -> Awaitable:
|
|
1164
|
+
def ping(self, message=None) -> Awaitable[bool]:
|
|
1165
1165
|
"""
|
|
1166
|
-
Ping the Redis server
|
|
1166
|
+
Ping the Redis server to test connectivity.
|
|
1167
|
+
|
|
1168
|
+
Sends a PING command to the Redis server and returns True if the server
|
|
1169
|
+
responds with "PONG".
|
|
1167
1170
|
"""
|
|
1168
1171
|
args = ["PING", message] if message is not None else ["PING"]
|
|
1169
1172
|
return self.execute_command(*args)
|
|
@@ -1239,6 +1242,7 @@ class PubSub:
|
|
|
1239
1242
|
*,
|
|
1240
1243
|
exception_handler: Optional["PSWorkerThreadExcHandlerT"] = None,
|
|
1241
1244
|
poll_timeout: float = 1.0,
|
|
1245
|
+
pubsub=None,
|
|
1242
1246
|
) -> None:
|
|
1243
1247
|
"""Process pub/sub messages using registered callbacks.
|
|
1244
1248
|
|
|
@@ -1263,9 +1267,14 @@ class PubSub:
|
|
|
1263
1267
|
await self.connect()
|
|
1264
1268
|
while True:
|
|
1265
1269
|
try:
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1270
|
+
if pubsub is None:
|
|
1271
|
+
await self.get_message(
|
|
1272
|
+
ignore_subscribe_messages=True, timeout=poll_timeout
|
|
1273
|
+
)
|
|
1274
|
+
else:
|
|
1275
|
+
await pubsub.get_message(
|
|
1276
|
+
ignore_subscribe_messages=True, timeout=poll_timeout
|
|
1277
|
+
)
|
|
1269
1278
|
except asyncio.CancelledError:
|
|
1270
1279
|
raise
|
|
1271
1280
|
except BaseException as e:
|
|
@@ -409,6 +409,7 @@ class RedisCluster(AbstractRedis, AbstractRedisCluster, AsyncRedisClusterCommand
|
|
|
409
409
|
else:
|
|
410
410
|
self._event_dispatcher = event_dispatcher
|
|
411
411
|
|
|
412
|
+
self.startup_nodes = startup_nodes
|
|
412
413
|
self.nodes_manager = NodesManager(
|
|
413
414
|
startup_nodes,
|
|
414
415
|
require_full_coverage,
|
|
@@ -2253,7 +2254,10 @@ class TransactionStrategy(AbstractStrategy):
|
|
|
2253
2254
|
await self._pipe.cluster_client.nodes_manager.initialize()
|
|
2254
2255
|
self.reinitialize_counter = 0
|
|
2255
2256
|
else:
|
|
2256
|
-
|
|
2257
|
+
if isinstance(error, AskError):
|
|
2258
|
+
self._pipe.cluster_client.nodes_manager.update_moved_exception(
|
|
2259
|
+
error
|
|
2260
|
+
)
|
|
2257
2261
|
|
|
2258
2262
|
self._executing = False
|
|
2259
2263
|
|
|
@@ -213,6 +213,7 @@ class AbstractConnection:
|
|
|
213
213
|
self._connect_callbacks: List[weakref.WeakMethod[ConnectCallbackT]] = []
|
|
214
214
|
self._buffer_cutoff = 6000
|
|
215
215
|
self._re_auth_token: Optional[TokenInterface] = None
|
|
216
|
+
self._should_reconnect = False
|
|
216
217
|
|
|
217
218
|
try:
|
|
218
219
|
p = int(protocol)
|
|
@@ -343,6 +344,12 @@ class AbstractConnection:
|
|
|
343
344
|
if task and inspect.isawaitable(task):
|
|
344
345
|
await task
|
|
345
346
|
|
|
347
|
+
def mark_for_reconnect(self):
|
|
348
|
+
self._should_reconnect = True
|
|
349
|
+
|
|
350
|
+
def should_reconnect(self):
|
|
351
|
+
return self._should_reconnect
|
|
352
|
+
|
|
346
353
|
@abstractmethod
|
|
347
354
|
async def _connect(self):
|
|
348
355
|
pass
|
|
@@ -1240,6 +1247,9 @@ class ConnectionPool:
|
|
|
1240
1247
|
# Connections should always be returned to the correct pool,
|
|
1241
1248
|
# not doing so is an error that will cause an exception here.
|
|
1242
1249
|
self._in_use_connections.remove(connection)
|
|
1250
|
+
if connection.should_reconnect():
|
|
1251
|
+
await connection.disconnect()
|
|
1252
|
+
|
|
1243
1253
|
self._available_connections.append(connection)
|
|
1244
1254
|
await self._event_dispatcher.dispatch_async(
|
|
1245
1255
|
AsyncAfterConnectionReleasedEvent(connection)
|
|
@@ -1267,6 +1277,14 @@ class ConnectionPool:
|
|
|
1267
1277
|
if exc:
|
|
1268
1278
|
raise exc
|
|
1269
1279
|
|
|
1280
|
+
async def update_active_connections_for_reconnect(self):
|
|
1281
|
+
"""
|
|
1282
|
+
Mark all active connections for reconnect.
|
|
1283
|
+
"""
|
|
1284
|
+
async with self._lock:
|
|
1285
|
+
for conn in self._in_use_connections:
|
|
1286
|
+
conn.mark_for_reconnect()
|
|
1287
|
+
|
|
1270
1288
|
async def aclose(self) -> None:
|
|
1271
1289
|
"""Close the pool, disconnecting all connections"""
|
|
1272
1290
|
await self.disconnect()
|
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
from abc import ABC, abstractmethod
|
|
3
|
+
from concurrent.futures import ThreadPoolExecutor
|
|
4
|
+
from typing import Any, Mapping, Optional, Union
|
|
5
|
+
|
|
6
|
+
from redis.http.http_client import HttpClient, HttpResponse
|
|
7
|
+
|
|
8
|
+
DEFAULT_USER_AGENT = "HttpClient/1.0 (+https://example.invalid)"
|
|
9
|
+
DEFAULT_TIMEOUT = 30.0
|
|
10
|
+
RETRY_STATUS_CODES = {429, 500, 502, 503, 504}
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class AsyncHTTPClient(ABC):
|
|
14
|
+
@abstractmethod
|
|
15
|
+
async def get(
|
|
16
|
+
self,
|
|
17
|
+
path: str,
|
|
18
|
+
params: Optional[
|
|
19
|
+
Mapping[str, Union[None, str, int, float, bool, list, tuple]]
|
|
20
|
+
] = None,
|
|
21
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
22
|
+
timeout: Optional[float] = None,
|
|
23
|
+
expect_json: bool = True,
|
|
24
|
+
) -> Union[HttpResponse, Any]:
|
|
25
|
+
"""
|
|
26
|
+
Invoke HTTP GET request."""
|
|
27
|
+
pass
|
|
28
|
+
|
|
29
|
+
@abstractmethod
|
|
30
|
+
async def delete(
|
|
31
|
+
self,
|
|
32
|
+
path: str,
|
|
33
|
+
params: Optional[
|
|
34
|
+
Mapping[str, Union[None, str, int, float, bool, list, tuple]]
|
|
35
|
+
] = None,
|
|
36
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
37
|
+
timeout: Optional[float] = None,
|
|
38
|
+
expect_json: bool = True,
|
|
39
|
+
) -> Union[HttpResponse, Any]:
|
|
40
|
+
"""
|
|
41
|
+
Invoke HTTP DELETE request."""
|
|
42
|
+
pass
|
|
43
|
+
|
|
44
|
+
@abstractmethod
|
|
45
|
+
async def post(
|
|
46
|
+
self,
|
|
47
|
+
path: str,
|
|
48
|
+
json_body: Optional[Any] = None,
|
|
49
|
+
data: Optional[Union[bytes, str]] = None,
|
|
50
|
+
params: Optional[
|
|
51
|
+
Mapping[str, Union[None, str, int, float, bool, list, tuple]]
|
|
52
|
+
] = None,
|
|
53
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
54
|
+
timeout: Optional[float] = None,
|
|
55
|
+
expect_json: bool = True,
|
|
56
|
+
) -> Union[HttpResponse, Any]:
|
|
57
|
+
"""
|
|
58
|
+
Invoke HTTP POST request."""
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
@abstractmethod
|
|
62
|
+
async def put(
|
|
63
|
+
self,
|
|
64
|
+
path: str,
|
|
65
|
+
json_body: Optional[Any] = None,
|
|
66
|
+
data: Optional[Union[bytes, str]] = None,
|
|
67
|
+
params: Optional[
|
|
68
|
+
Mapping[str, Union[None, str, int, float, bool, list, tuple]]
|
|
69
|
+
] = None,
|
|
70
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
71
|
+
timeout: Optional[float] = None,
|
|
72
|
+
expect_json: bool = True,
|
|
73
|
+
) -> Union[HttpResponse, Any]:
|
|
74
|
+
"""
|
|
75
|
+
Invoke HTTP PUT request."""
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
@abstractmethod
|
|
79
|
+
async def patch(
|
|
80
|
+
self,
|
|
81
|
+
path: str,
|
|
82
|
+
json_body: Optional[Any] = None,
|
|
83
|
+
data: Optional[Union[bytes, str]] = None,
|
|
84
|
+
params: Optional[
|
|
85
|
+
Mapping[str, Union[None, str, int, float, bool, list, tuple]]
|
|
86
|
+
] = None,
|
|
87
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
88
|
+
timeout: Optional[float] = None,
|
|
89
|
+
expect_json: bool = True,
|
|
90
|
+
) -> Union[HttpResponse, Any]:
|
|
91
|
+
"""
|
|
92
|
+
Invoke HTTP PATCH request."""
|
|
93
|
+
pass
|
|
94
|
+
|
|
95
|
+
@abstractmethod
|
|
96
|
+
async def request(
|
|
97
|
+
self,
|
|
98
|
+
method: str,
|
|
99
|
+
path: str,
|
|
100
|
+
params: Optional[
|
|
101
|
+
Mapping[str, Union[None, str, int, float, bool, list, tuple]]
|
|
102
|
+
] = None,
|
|
103
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
104
|
+
body: Optional[Union[bytes, str]] = None,
|
|
105
|
+
timeout: Optional[float] = None,
|
|
106
|
+
) -> HttpResponse:
|
|
107
|
+
"""
|
|
108
|
+
Invoke HTTP request with given method."""
|
|
109
|
+
pass
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class AsyncHTTPClientWrapper(AsyncHTTPClient):
|
|
113
|
+
"""
|
|
114
|
+
An async wrapper around sync HTTP client with thread pool execution.
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
def __init__(self, client: HttpClient, max_workers: int = 10) -> None:
|
|
118
|
+
"""
|
|
119
|
+
Initialize a new HTTP client instance.
|
|
120
|
+
|
|
121
|
+
Args:
|
|
122
|
+
client: Sync HTTP client instance.
|
|
123
|
+
max_workers: Maximum number of concurrent requests.
|
|
124
|
+
|
|
125
|
+
The client supports both regular HTTPS with server verification and mutual TLS
|
|
126
|
+
authentication. For server verification, provide CA certificate information via
|
|
127
|
+
ca_file, ca_path or ca_data. For mutual TLS, additionally provide a client
|
|
128
|
+
certificate and key via client_cert_file and client_key_file.
|
|
129
|
+
"""
|
|
130
|
+
self.client = client
|
|
131
|
+
self._executor = ThreadPoolExecutor(max_workers=max_workers)
|
|
132
|
+
|
|
133
|
+
async def get(
|
|
134
|
+
self,
|
|
135
|
+
path: str,
|
|
136
|
+
params: Optional[
|
|
137
|
+
Mapping[str, Union[None, str, int, float, bool, list, tuple]]
|
|
138
|
+
] = None,
|
|
139
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
140
|
+
timeout: Optional[float] = None,
|
|
141
|
+
expect_json: bool = True,
|
|
142
|
+
) -> Union[HttpResponse, Any]:
|
|
143
|
+
loop = asyncio.get_event_loop()
|
|
144
|
+
return await loop.run_in_executor(
|
|
145
|
+
self._executor, self.client.get, path, params, headers, timeout, expect_json
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
async def delete(
|
|
149
|
+
self,
|
|
150
|
+
path: str,
|
|
151
|
+
params: Optional[
|
|
152
|
+
Mapping[str, Union[None, str, int, float, bool, list, tuple]]
|
|
153
|
+
] = None,
|
|
154
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
155
|
+
timeout: Optional[float] = None,
|
|
156
|
+
expect_json: bool = True,
|
|
157
|
+
) -> Union[HttpResponse, Any]:
|
|
158
|
+
loop = asyncio.get_event_loop()
|
|
159
|
+
return await loop.run_in_executor(
|
|
160
|
+
self._executor,
|
|
161
|
+
self.client.delete,
|
|
162
|
+
path,
|
|
163
|
+
params,
|
|
164
|
+
headers,
|
|
165
|
+
timeout,
|
|
166
|
+
expect_json,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
async def post(
|
|
170
|
+
self,
|
|
171
|
+
path: str,
|
|
172
|
+
json_body: Optional[Any] = None,
|
|
173
|
+
data: Optional[Union[bytes, str]] = None,
|
|
174
|
+
params: Optional[
|
|
175
|
+
Mapping[str, Union[None, str, int, float, bool, list, tuple]]
|
|
176
|
+
] = None,
|
|
177
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
178
|
+
timeout: Optional[float] = None,
|
|
179
|
+
expect_json: bool = True,
|
|
180
|
+
) -> Union[HttpResponse, Any]:
|
|
181
|
+
loop = asyncio.get_event_loop()
|
|
182
|
+
return await loop.run_in_executor(
|
|
183
|
+
self._executor,
|
|
184
|
+
self.client.post,
|
|
185
|
+
path,
|
|
186
|
+
json_body,
|
|
187
|
+
data,
|
|
188
|
+
params,
|
|
189
|
+
headers,
|
|
190
|
+
timeout,
|
|
191
|
+
expect_json,
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
async def put(
|
|
195
|
+
self,
|
|
196
|
+
path: str,
|
|
197
|
+
json_body: Optional[Any] = None,
|
|
198
|
+
data: Optional[Union[bytes, str]] = None,
|
|
199
|
+
params: Optional[
|
|
200
|
+
Mapping[str, Union[None, str, int, float, bool, list, tuple]]
|
|
201
|
+
] = None,
|
|
202
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
203
|
+
timeout: Optional[float] = None,
|
|
204
|
+
expect_json: bool = True,
|
|
205
|
+
) -> Union[HttpResponse, Any]:
|
|
206
|
+
loop = asyncio.get_event_loop()
|
|
207
|
+
return await loop.run_in_executor(
|
|
208
|
+
self._executor,
|
|
209
|
+
self.client.put,
|
|
210
|
+
path,
|
|
211
|
+
json_body,
|
|
212
|
+
data,
|
|
213
|
+
params,
|
|
214
|
+
headers,
|
|
215
|
+
timeout,
|
|
216
|
+
expect_json,
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
async def patch(
|
|
220
|
+
self,
|
|
221
|
+
path: str,
|
|
222
|
+
json_body: Optional[Any] = None,
|
|
223
|
+
data: Optional[Union[bytes, str]] = None,
|
|
224
|
+
params: Optional[
|
|
225
|
+
Mapping[str, Union[None, str, int, float, bool, list, tuple]]
|
|
226
|
+
] = None,
|
|
227
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
228
|
+
timeout: Optional[float] = None,
|
|
229
|
+
expect_json: bool = True,
|
|
230
|
+
) -> Union[HttpResponse, Any]:
|
|
231
|
+
loop = asyncio.get_event_loop()
|
|
232
|
+
return await loop.run_in_executor(
|
|
233
|
+
self._executor,
|
|
234
|
+
self.client.patch,
|
|
235
|
+
path,
|
|
236
|
+
json_body,
|
|
237
|
+
data,
|
|
238
|
+
params,
|
|
239
|
+
headers,
|
|
240
|
+
timeout,
|
|
241
|
+
expect_json,
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
async def request(
|
|
245
|
+
self,
|
|
246
|
+
method: str,
|
|
247
|
+
path: str,
|
|
248
|
+
params: Optional[
|
|
249
|
+
Mapping[str, Union[None, str, int, float, bool, list, tuple]]
|
|
250
|
+
] = None,
|
|
251
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
252
|
+
body: Optional[Union[bytes, str]] = None,
|
|
253
|
+
timeout: Optional[float] = None,
|
|
254
|
+
) -> HttpResponse:
|
|
255
|
+
loop = asyncio.get_event_loop()
|
|
256
|
+
return await loop.run_in_executor(
|
|
257
|
+
self._executor,
|
|
258
|
+
self.client.request,
|
|
259
|
+
method,
|
|
260
|
+
path,
|
|
261
|
+
params,
|
|
262
|
+
headers,
|
|
263
|
+
body,
|
|
264
|
+
timeout,
|
|
265
|
+
)
|