redis 7.0.0b3__tar.gz → 7.0.1__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.0b3 → redis-7.0.1}/PKG-INFO +15 -4
- {redis-7.0.0b3 → redis-7.0.1}/README.md +14 -3
- redis-7.0.1/dev_requirements.txt +30 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/__init__.py +1 -1
- {redis-7.0.0b3 → redis-7.0.1}/redis/_parsers/base.py +6 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/_parsers/helpers.py +64 -6
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/connection.py +1 -1
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/multidb/client.py +2 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/multidb/config.py +2 -2
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/multidb/healthcheck.py +4 -11
- {redis-7.0.0b3 → redis-7.0.1}/redis/client.py +27 -24
- {redis-7.0.0b3 → redis-7.0.1}/redis/cluster.py +6 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/core.py +54 -26
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/json/commands.py +2 -2
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/search/__init__.py +2 -2
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/search/aggregation.py +24 -26
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/search/commands.py +10 -10
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/search/query.py +12 -12
- {redis-7.0.0b3 → redis-7.0.1}/redis/connection.py +1613 -1263
- {redis-7.0.0b3 → redis-7.0.1}/redis/exceptions.py +8 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/maint_notifications.py +18 -7
- {redis-7.0.0b3 → redis-7.0.1}/redis/multidb/client.py +2 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/multidb/config.py +2 -2
- {redis-7.0.0b3 → redis-7.0.1}/redis/multidb/healthcheck.py +4 -11
- {redis-7.0.0b3 → redis-7.0.1}/redis/utils.py +20 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/conftest.py +9 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_commands.py +37 -7
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_connection_pool.py +28 -5
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_multidb/test_config.py +2 -2
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_multidb/test_healthcheck.py +8 -8
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_search.py +17 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_commands.py +57 -13
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_connection_pool.py +37 -1
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_credentials.py +6 -1
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_maint_notifications.py +5 -2
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_maint_notifications_handling.py +111 -98
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_multidb/test_config.py +2 -2
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_multidb/test_healthcheck.py +8 -8
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_multiprocessing.py +8 -0
- redis-7.0.1/tests/test_parsers/test_errors.py +167 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_parsers/test_helpers.py +21 -1
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_pubsub.py +10 -2
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_scenario/conftest.py +0 -4
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_search.py +15 -0
- redis-7.0.0b3/dev_requirements.txt +0 -17
- {redis-7.0.0b3 → redis-7.0.1}/.gitignore +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/LICENSE +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/pyproject.toml +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/_parsers/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/_parsers/commands.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/_parsers/encoders.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/_parsers/hiredis.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/_parsers/resp2.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/_parsers/resp3.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/_parsers/socket.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/client.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/cluster.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/http/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/http/http_client.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/lock.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/multidb/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/multidb/command_executor.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/multidb/database.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/multidb/event.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/multidb/failover.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/multidb/failure_detector.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/retry.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/sentinel.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/asyncio/utils.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/auth/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/auth/err.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/auth/idp.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/auth/token.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/auth/token_manager.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/background.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/backoff.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/cache.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/bf/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/bf/commands.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/bf/info.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/cluster.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/helpers.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/json/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/json/_util.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/json/decoders.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/json/path.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/redismodules.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/search/_util.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/search/dialect.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/search/document.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/search/field.py +2 -2
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/search/index_definition.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/search/profile_information.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/search/querystring.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/search/reducers.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/search/result.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/search/suggestion.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/sentinel.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/timeseries/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/timeseries/commands.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/timeseries/info.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/timeseries/utils.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/vectorset/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/vectorset/commands.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/commands/vectorset/utils.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/crc.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/credentials.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/data_structure.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/event.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/http/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/http/http_client.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/lock.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/multidb/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/multidb/circuit.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/multidb/command_executor.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/multidb/database.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/multidb/event.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/multidb/exception.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/multidb/failover.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/multidb/failure_detector.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/ocsp.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/py.typed +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/retry.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/sentinel.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/redis/typing.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/entraid_utils.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/mocks.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/ssl_utils.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/compat.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/conftest.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/mocks.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_bloom.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_cluster.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_cluster_transaction.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_connect.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_connection.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_credentials.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_cwe_404.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_encoding.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_hash.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_json.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_lock.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_monitor.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_multidb/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_multidb/conftest.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_multidb/test_client.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_multidb/test_command_executor.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_multidb/test_failover.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_multidb/test_failure_detector.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_multidb/test_pipeline.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_pipeline.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_pubsub.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_retry.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_scenario/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_scenario/conftest.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_scenario/test_active_active.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_scripting.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_sentinel.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_sentinel_managed_connection.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_ssl.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_timeseries.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_usage_counter.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_utils.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/test_vsets.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/testdata/jsontestdata.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/testdata/titles.csv +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_asyncio/testdata/will_play_text.csv.bz2 +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_auth/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_auth/test_token.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_auth/test_token_manager.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_background.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_backoff.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_bloom.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_cache.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_cluster.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_cluster_transaction.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_command_parser.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_connect.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_connection.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_data_structure.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_encoding.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_event.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_function.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_hash.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_helpers.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_http/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_http/test_http_client.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_json.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_lock.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_max_connections_error.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_monitor.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_multidb/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_multidb/conftest.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_multidb/test_circuit.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_multidb/test_client.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_multidb/test_command_executor.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_multidb/test_failover.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_multidb/test_failure_detector.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_multidb/test_pipeline.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_pipeline.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_retry.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_scenario/__init__.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_scenario/fault_injector_client.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_scenario/maint_notifications_helpers.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_scenario/test_active_active.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_scenario/test_maint_notifications.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_scripting.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_sentinel.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_sentinel_managed_connection.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_ssl.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_timeseries.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_utils.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/test_vsets.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/testdata/jsontestdata.py +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/tests/testdata/titles.csv +0 -0
- {redis-7.0.0b3 → redis-7.0.1}/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.1
|
|
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
|
|
@@ -55,8 +55,9 @@ The Python interface to the Redis key-value store.
|
|
|
55
55
|
|
|
56
56
|
---------------------------------------------
|
|
57
57
|
|
|
58
|
-
**Note:** redis-py 5.0
|
|
59
|
-
**Note:** redis-py 6.1.0
|
|
58
|
+
**Note:** redis-py 5.0 is the last version of redis-py that supports Python 3.7, as it has reached [end of life](https://devguide.python.org/versions/). redis-py 5.1 supports Python 3.8+.<br>
|
|
59
|
+
**Note:** redis-py 6.1.0 is the last version of redis-py that supports Python 3.8, as it has reached [end of life](https://devguide.python.org/versions/). redis-py 6.2.0 supports Python 3.9+.
|
|
60
|
+
|
|
60
61
|
---------------------------------------------
|
|
61
62
|
|
|
62
63
|
## How do I Redis?
|
|
@@ -101,7 +102,7 @@ Looking for a high-level library to handle object mapping? See [redis-om-python]
|
|
|
101
102
|
|
|
102
103
|
## Supported Redis Versions
|
|
103
104
|
|
|
104
|
-
The most recent version of this library supports Redis version [7.2](https://github.com/redis/redis/blob/7.2/00-RELEASENOTES), [7.4](https://github.com/redis/redis/blob/7.4/00-RELEASENOTES)
|
|
105
|
+
The most recent version of this library supports Redis version [7.2](https://github.com/redis/redis/blob/7.2/00-RELEASENOTES), [7.4](https://github.com/redis/redis/blob/7.4/00-RELEASENOTES), [8.0](https://github.com/redis/redis/blob/8.0/00-RELEASENOTES) and [8.2](https://github.com/redis/redis/blob/8.2/00-RELEASENOTES).
|
|
105
106
|
|
|
106
107
|
The table below highlights version compatibility of the most-recent library versions and redis versions.
|
|
107
108
|
|
|
@@ -235,6 +236,16 @@ By default, the client now overrides the server-side dialect with version 2, aut
|
|
|
235
236
|
|
|
236
237
|
You can find further details in the [query dialect documentation](https://redis.io/docs/latest/develop/interact/search-and-query/advanced-concepts/dialects/).
|
|
237
238
|
|
|
239
|
+
### Multi-database client (Active-Active)
|
|
240
|
+
|
|
241
|
+
The multi-database client allows your application to connect to multiple Redis databases, which are typically replicas of each other. It is designed to work with Redis Software and Redis Cloud Active-Active setups. The client continuously monitors database health, detects failures, and automatically fails over to the next healthy database using a configurable strategy. When the original database becomes healthy again, the client can automatically switch back to it.<br>
|
|
242
|
+
This is useful when:
|
|
243
|
+
|
|
244
|
+
1. You have more than one Redis deployment. This might include two independent Redis servers or two or more Redis databases replicated across multiple [active-active Redis Enterprise](https://redis.io/docs/latest/operate/rs/databases/active-active/) clusters.
|
|
245
|
+
2. You want your application to connect to one deployment at a time and to fail over to the next available deployment if the first deployment becomes unavailable.
|
|
246
|
+
|
|
247
|
+
For the complete failover configuration options and examples, see the [Multi-database client docs](https://redis.readthedocs.io/en/latest/multi_database.html).
|
|
248
|
+
|
|
238
249
|
---------------------------------------------
|
|
239
250
|
|
|
240
251
|
### Author
|
|
@@ -13,8 +13,9 @@ The Python interface to the Redis key-value store.
|
|
|
13
13
|
|
|
14
14
|
---------------------------------------------
|
|
15
15
|
|
|
16
|
-
**Note:** redis-py 5.0
|
|
17
|
-
**Note:** redis-py 6.1.0
|
|
16
|
+
**Note:** redis-py 5.0 is the last version of redis-py that supports Python 3.7, as it has reached [end of life](https://devguide.python.org/versions/). redis-py 5.1 supports Python 3.8+.<br>
|
|
17
|
+
**Note:** redis-py 6.1.0 is the last version of redis-py that supports Python 3.8, as it has reached [end of life](https://devguide.python.org/versions/). redis-py 6.2.0 supports Python 3.9+.
|
|
18
|
+
|
|
18
19
|
---------------------------------------------
|
|
19
20
|
|
|
20
21
|
## How do I Redis?
|
|
@@ -59,7 +60,7 @@ Looking for a high-level library to handle object mapping? See [redis-om-python]
|
|
|
59
60
|
|
|
60
61
|
## Supported Redis Versions
|
|
61
62
|
|
|
62
|
-
The most recent version of this library supports Redis version [7.2](https://github.com/redis/redis/blob/7.2/00-RELEASENOTES), [7.4](https://github.com/redis/redis/blob/7.4/00-RELEASENOTES)
|
|
63
|
+
The most recent version of this library supports Redis version [7.2](https://github.com/redis/redis/blob/7.2/00-RELEASENOTES), [7.4](https://github.com/redis/redis/blob/7.4/00-RELEASENOTES), [8.0](https://github.com/redis/redis/blob/8.0/00-RELEASENOTES) and [8.2](https://github.com/redis/redis/blob/8.2/00-RELEASENOTES).
|
|
63
64
|
|
|
64
65
|
The table below highlights version compatibility of the most-recent library versions and redis versions.
|
|
65
66
|
|
|
@@ -193,6 +194,16 @@ By default, the client now overrides the server-side dialect with version 2, aut
|
|
|
193
194
|
|
|
194
195
|
You can find further details in the [query dialect documentation](https://redis.io/docs/latest/develop/interact/search-and-query/advanced-concepts/dialects/).
|
|
195
196
|
|
|
197
|
+
### Multi-database client (Active-Active)
|
|
198
|
+
|
|
199
|
+
The multi-database client allows your application to connect to multiple Redis databases, which are typically replicas of each other. It is designed to work with Redis Software and Redis Cloud Active-Active setups. The client continuously monitors database health, detects failures, and automatically fails over to the next healthy database using a configurable strategy. When the original database becomes healthy again, the client can automatically switch back to it.<br>
|
|
200
|
+
This is useful when:
|
|
201
|
+
|
|
202
|
+
1. You have more than one Redis deployment. This might include two independent Redis servers or two or more Redis databases replicated across multiple [active-active Redis Enterprise](https://redis.io/docs/latest/operate/rs/databases/active-active/) clusters.
|
|
203
|
+
2. You want your application to connect to one deployment at a time and to fail over to the next available deployment if the first deployment becomes unavailable.
|
|
204
|
+
|
|
205
|
+
For the complete failover configuration options and examples, see the [Multi-database client docs](https://redis.readthedocs.io/en/latest/multi_database.html).
|
|
206
|
+
|
|
196
207
|
---------------------------------------------
|
|
197
208
|
|
|
198
209
|
### Author
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
build
|
|
2
|
+
build==1.2.2.post1 ; platform_python_implementation == "PyPy" or python_version < "3.10"
|
|
3
|
+
click==8.0.4
|
|
4
|
+
invoke==2.2.0
|
|
5
|
+
mock
|
|
6
|
+
mock==5.1.0 ; platform_python_implementation == "PyPy" or python_version < "3.10"
|
|
7
|
+
packaging>=20.4
|
|
8
|
+
packaging==24.2 ; platform_python_implementation == "PyPy" or python_version < "3.10"
|
|
9
|
+
|
|
10
|
+
pytest
|
|
11
|
+
pytest==8.3.4 ; platform_python_implementation == "PyPy" or python_version < "3.10"
|
|
12
|
+
pytest-asyncio>=0.23.0
|
|
13
|
+
pytest-asyncio==1.1.0 ; platform_python_implementation == "PyPy" or python_version < "3.10"
|
|
14
|
+
pytest-cov
|
|
15
|
+
pytest-cov==6.0.0 ; platform_python_implementation == "PyPy" or python_version < "3.10"
|
|
16
|
+
coverage==7.6.12 ; platform_python_implementation == "PyPy" or python_version < "3.10"
|
|
17
|
+
pytest-profiling==1.8.1
|
|
18
|
+
pytest-timeout
|
|
19
|
+
pytest-timeout==2.3.1 ; platform_python_implementation == "PyPy" or python_version < "3.10"
|
|
20
|
+
|
|
21
|
+
ruff==0.9.6
|
|
22
|
+
ujson>=4.2.0
|
|
23
|
+
uvloop<=0.21.0; platform_python_implementation == "CPython"
|
|
24
|
+
vulture>=2.3.0
|
|
25
|
+
|
|
26
|
+
numpy>=1.24.0 ; platform_python_implementation == "CPython"
|
|
27
|
+
numpy>=1.24.0,<2.0 ; platform_python_implementation == "PyPy" or python_version < "3.10"
|
|
28
|
+
|
|
29
|
+
redis-entraid==1.0.0
|
|
30
|
+
pybreaker>=1.4.0
|
|
@@ -27,6 +27,7 @@ from ..exceptions import (
|
|
|
27
27
|
ClusterDownError,
|
|
28
28
|
ConnectionError,
|
|
29
29
|
ExecAbortError,
|
|
30
|
+
ExternalAuthProviderError,
|
|
30
31
|
MasterDownError,
|
|
31
32
|
ModuleError,
|
|
32
33
|
MovedError,
|
|
@@ -60,6 +61,10 @@ NO_AUTH_SET_ERROR = {
|
|
|
60
61
|
"Client sent AUTH, but no password is set": AuthenticationError,
|
|
61
62
|
}
|
|
62
63
|
|
|
64
|
+
EXTERNAL_AUTH_PROVIDER_ERROR = {
|
|
65
|
+
"problem with LDAP service": ExternalAuthProviderError,
|
|
66
|
+
}
|
|
67
|
+
|
|
63
68
|
logger = logging.getLogger(__name__)
|
|
64
69
|
|
|
65
70
|
|
|
@@ -81,6 +86,7 @@ class BaseParser(ABC):
|
|
|
81
86
|
NO_SUCH_MODULE_ERROR: ModuleError,
|
|
82
87
|
MODULE_UNLOAD_NOT_POSSIBLE_ERROR: ModuleError,
|
|
83
88
|
**NO_AUTH_SET_ERROR,
|
|
89
|
+
**EXTERNAL_AUTH_PROVIDER_ERROR,
|
|
84
90
|
},
|
|
85
91
|
"OOM": OutOfMemoryError,
|
|
86
92
|
"WRONGPASS": AuthenticationError,
|
|
@@ -224,6 +224,39 @@ def zset_score_pairs(response, **options):
|
|
|
224
224
|
return list(zip(it, map(score_cast_func, it)))
|
|
225
225
|
|
|
226
226
|
|
|
227
|
+
def zset_score_for_rank(response, **options):
|
|
228
|
+
"""
|
|
229
|
+
If ``withscores`` is specified in the options, return the response as
|
|
230
|
+
a [value, score] pair
|
|
231
|
+
"""
|
|
232
|
+
if not response or not options.get("withscore"):
|
|
233
|
+
return response
|
|
234
|
+
score_cast_func = options.get("score_cast_func", float)
|
|
235
|
+
return [response[0], score_cast_func(response[1])]
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def zset_score_pairs_resp3(response, **options):
|
|
239
|
+
"""
|
|
240
|
+
If ``withscores`` is specified in the options, return the response as
|
|
241
|
+
a list of [value, score] pairs
|
|
242
|
+
"""
|
|
243
|
+
if not response or not options.get("withscores"):
|
|
244
|
+
return response
|
|
245
|
+
score_cast_func = options.get("score_cast_func", float)
|
|
246
|
+
return [[name, score_cast_func(val)] for name, val in response]
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
def zset_score_for_rank_resp3(response, **options):
|
|
250
|
+
"""
|
|
251
|
+
If ``withscores`` is specified in the options, return the response as
|
|
252
|
+
a [value, score] pair
|
|
253
|
+
"""
|
|
254
|
+
if not response or not options.get("withscore"):
|
|
255
|
+
return response
|
|
256
|
+
score_cast_func = options.get("score_cast_func", float)
|
|
257
|
+
return [response[0], score_cast_func(response[1])]
|
|
258
|
+
|
|
259
|
+
|
|
227
260
|
def sort_return_tuples(response, **options):
|
|
228
261
|
"""
|
|
229
262
|
If ``groups`` is specified, return the response as a list of
|
|
@@ -349,8 +382,22 @@ def parse_zadd(response, **options):
|
|
|
349
382
|
def parse_client_list(response, **options):
|
|
350
383
|
clients = []
|
|
351
384
|
for c in str_if_bytes(response).splitlines():
|
|
352
|
-
|
|
353
|
-
|
|
385
|
+
client_dict = {}
|
|
386
|
+
tokens = c.split(" ")
|
|
387
|
+
last_key = None
|
|
388
|
+
for token in tokens:
|
|
389
|
+
if "=" in token:
|
|
390
|
+
# Values might contain '='
|
|
391
|
+
key, value = token.split("=", 1)
|
|
392
|
+
client_dict[key] = value
|
|
393
|
+
last_key = key
|
|
394
|
+
else:
|
|
395
|
+
# Values may include spaces. For instance, when running Redis via a Unix socket — such as
|
|
396
|
+
# "/tmp/redis sock/redis.sock" — the addr or laddr field will include a space.
|
|
397
|
+
client_dict[last_key] += " " + token
|
|
398
|
+
|
|
399
|
+
if client_dict:
|
|
400
|
+
clients.append(client_dict)
|
|
354
401
|
return clients
|
|
355
402
|
|
|
356
403
|
|
|
@@ -797,10 +844,14 @@ _RedisCallbacksRESP2 = {
|
|
|
797
844
|
"SDIFF SINTER SMEMBERS SUNION", lambda r: r and set(r) or set()
|
|
798
845
|
),
|
|
799
846
|
**string_keys_to_dict(
|
|
800
|
-
"ZDIFF ZINTER ZPOPMAX ZPOPMIN ZRANGE ZRANGEBYSCORE
|
|
801
|
-
"ZREVRANGEBYSCORE
|
|
847
|
+
"ZDIFF ZINTER ZPOPMAX ZPOPMIN ZRANGE ZRANGEBYSCORE ZREVRANGE "
|
|
848
|
+
"ZREVRANGEBYSCORE ZUNION",
|
|
802
849
|
zset_score_pairs,
|
|
803
850
|
),
|
|
851
|
+
**string_keys_to_dict(
|
|
852
|
+
"ZREVRANK ZRANK",
|
|
853
|
+
zset_score_for_rank,
|
|
854
|
+
),
|
|
804
855
|
**string_keys_to_dict("ZINCRBY ZSCORE", float_or_none),
|
|
805
856
|
**string_keys_to_dict("BGREWRITEAOF BGSAVE", lambda r: True),
|
|
806
857
|
**string_keys_to_dict("BLPOP BRPOP", lambda r: r and tuple(r) or None),
|
|
@@ -844,10 +895,17 @@ _RedisCallbacksRESP3 = {
|
|
|
844
895
|
"SDIFF SINTER SMEMBERS SUNION", lambda r: r and set(r) or set()
|
|
845
896
|
),
|
|
846
897
|
**string_keys_to_dict(
|
|
847
|
-
"ZRANGE ZINTER ZPOPMAX ZPOPMIN
|
|
848
|
-
"ZUNION HGETALL XREADGROUP",
|
|
898
|
+
"ZRANGE ZINTER ZPOPMAX ZPOPMIN HGETALL XREADGROUP",
|
|
849
899
|
lambda r, **kwargs: r,
|
|
850
900
|
),
|
|
901
|
+
**string_keys_to_dict(
|
|
902
|
+
"ZRANGE ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE ZUNION",
|
|
903
|
+
zset_score_pairs_resp3,
|
|
904
|
+
),
|
|
905
|
+
**string_keys_to_dict(
|
|
906
|
+
"ZREVRANK ZRANK",
|
|
907
|
+
zset_score_for_rank_resp3,
|
|
908
|
+
),
|
|
851
909
|
**string_keys_to_dict("XREAD XREADGROUP", parse_xread_resp3),
|
|
852
910
|
"ACL LOG": lambda r: (
|
|
853
911
|
[
|
|
@@ -1356,7 +1356,7 @@ class BlockingConnectionPool(ConnectionPool):
|
|
|
1356
1356
|
def __init__(
|
|
1357
1357
|
self,
|
|
1358
1358
|
max_connections: int = 50,
|
|
1359
|
-
timeout: Optional[
|
|
1359
|
+
timeout: Optional[float] = 20,
|
|
1360
1360
|
connection_class: Type[AbstractConnection] = Connection,
|
|
1361
1361
|
queue_class: Type[asyncio.Queue] = asyncio.LifoQueue, # deprecated
|
|
1362
1362
|
**connection_kwargs,
|
|
@@ -14,10 +14,12 @@ from redis.multidb.circuit import CircuitBreaker
|
|
|
14
14
|
from redis.multidb.circuit import State as CBState
|
|
15
15
|
from redis.multidb.exception import NoValidDatabaseException, UnhealthyDatabaseException
|
|
16
16
|
from redis.typing import ChannelT, EncodableT, KeyT
|
|
17
|
+
from redis.utils import experimental
|
|
17
18
|
|
|
18
19
|
logger = logging.getLogger(__name__)
|
|
19
20
|
|
|
20
21
|
|
|
22
|
+
@experimental
|
|
21
23
|
class MultiDBClient(AsyncRedisModuleCommands, AsyncCoreCommands):
|
|
22
24
|
"""
|
|
23
25
|
Client that operates on multiple logical Redis databases.
|
|
@@ -20,9 +20,9 @@ from redis.asyncio.multidb.healthcheck import (
|
|
|
20
20
|
DEFAULT_HEALTH_CHECK_INTERVAL,
|
|
21
21
|
DEFAULT_HEALTH_CHECK_POLICY,
|
|
22
22
|
DEFAULT_HEALTH_CHECK_PROBES,
|
|
23
|
-
EchoHealthCheck,
|
|
24
23
|
HealthCheck,
|
|
25
24
|
HealthCheckPolicies,
|
|
25
|
+
PingHealthCheck,
|
|
26
26
|
)
|
|
27
27
|
from redis.asyncio.retry import Retry
|
|
28
28
|
from redis.backoff import ExponentialWithJitterBackoff, NoBackoff
|
|
@@ -203,7 +203,7 @@ class MultiDbConfig:
|
|
|
203
203
|
|
|
204
204
|
def default_health_checks(self) -> List[HealthCheck]:
|
|
205
205
|
return [
|
|
206
|
-
|
|
206
|
+
PingHealthCheck(),
|
|
207
207
|
]
|
|
208
208
|
|
|
209
209
|
def default_failover_strategy(self) -> AsyncFailoverStrategy:
|
|
@@ -170,26 +170,19 @@ class HealthCheckPolicies(Enum):
|
|
|
170
170
|
DEFAULT_HEALTH_CHECK_POLICY: HealthCheckPolicies = HealthCheckPolicies.HEALTHY_ALL
|
|
171
171
|
|
|
172
172
|
|
|
173
|
-
class
|
|
173
|
+
class PingHealthCheck(HealthCheck):
|
|
174
174
|
"""
|
|
175
|
-
Health check based on
|
|
175
|
+
Health check based on PING command.
|
|
176
176
|
"""
|
|
177
177
|
|
|
178
178
|
async def check_health(self, database) -> bool:
|
|
179
|
-
expected_message = ["healthcheck", b"healthcheck"]
|
|
180
|
-
|
|
181
179
|
if isinstance(database.client, Redis):
|
|
182
|
-
|
|
183
|
-
"ECHO", "healthcheck"
|
|
184
|
-
)
|
|
185
|
-
return actual_message in expected_message
|
|
180
|
+
return await database.client.execute_command("PING")
|
|
186
181
|
else:
|
|
187
182
|
# For a cluster checks if all nodes are healthy.
|
|
188
183
|
all_nodes = database.client.get_nodes()
|
|
189
184
|
for node in all_nodes:
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
if actual_message not in expected_message:
|
|
185
|
+
if not await node.redis_connection.execute_command("PING"):
|
|
193
186
|
return False
|
|
194
187
|
|
|
195
188
|
return True
|
|
@@ -58,7 +58,6 @@ from redis.exceptions import (
|
|
|
58
58
|
from redis.lock import Lock
|
|
59
59
|
from redis.maint_notifications import (
|
|
60
60
|
MaintNotificationsConfig,
|
|
61
|
-
MaintNotificationsPoolHandler,
|
|
62
61
|
)
|
|
63
62
|
from redis.retry import Retry
|
|
64
63
|
from redis.utils import (
|
|
@@ -278,6 +277,17 @@ class Redis(RedisModuleCommands, CoreCommands, SentinelCommands):
|
|
|
278
277
|
single_connection_client:
|
|
279
278
|
if `True`, connection pool is not used. In that case `Redis`
|
|
280
279
|
instance use is not thread safe.
|
|
280
|
+
decode_responses:
|
|
281
|
+
if `True`, the response will be decoded to utf-8.
|
|
282
|
+
Argument is ignored when connection_pool is provided.
|
|
283
|
+
maint_notifications_config:
|
|
284
|
+
configuration the pool to support maintenance notifications - see
|
|
285
|
+
`redis.maint_notifications.MaintNotificationsConfig` for details.
|
|
286
|
+
Only supported with RESP3
|
|
287
|
+
If not provided and protocol is RESP3, the maintenance notifications
|
|
288
|
+
will be enabled by default (logic is included in the connection pool
|
|
289
|
+
initialization).
|
|
290
|
+
Argument is ignored when connection_pool is provided.
|
|
281
291
|
"""
|
|
282
292
|
if event_dispatcher is None:
|
|
283
293
|
self._event_dispatcher = EventDispatcher()
|
|
@@ -354,6 +364,22 @@ class Redis(RedisModuleCommands, CoreCommands, SentinelCommands):
|
|
|
354
364
|
"cache_config": cache_config,
|
|
355
365
|
}
|
|
356
366
|
)
|
|
367
|
+
maint_notifications_enabled = (
|
|
368
|
+
maint_notifications_config and maint_notifications_config.enabled
|
|
369
|
+
)
|
|
370
|
+
if maint_notifications_enabled and protocol not in [
|
|
371
|
+
3,
|
|
372
|
+
"3",
|
|
373
|
+
]:
|
|
374
|
+
raise RedisError(
|
|
375
|
+
"Maintenance notifications handlers on connection are only supported with RESP version 3"
|
|
376
|
+
)
|
|
377
|
+
if maint_notifications_config:
|
|
378
|
+
kwargs.update(
|
|
379
|
+
{
|
|
380
|
+
"maint_notifications_config": maint_notifications_config,
|
|
381
|
+
}
|
|
382
|
+
)
|
|
357
383
|
connection_pool = ConnectionPool(**kwargs)
|
|
358
384
|
self._event_dispatcher.dispatch(
|
|
359
385
|
AfterPooledConnectionsInstantiationEvent(
|
|
@@ -377,23 +403,6 @@ class Redis(RedisModuleCommands, CoreCommands, SentinelCommands):
|
|
|
377
403
|
]:
|
|
378
404
|
raise RedisError("Client caching is only supported with RESP version 3")
|
|
379
405
|
|
|
380
|
-
if maint_notifications_config and self.connection_pool.get_protocol() not in [
|
|
381
|
-
3,
|
|
382
|
-
"3",
|
|
383
|
-
]:
|
|
384
|
-
raise RedisError(
|
|
385
|
-
"Push handlers on connection are only supported with RESP version 3"
|
|
386
|
-
)
|
|
387
|
-
if maint_notifications_config and maint_notifications_config.enabled:
|
|
388
|
-
self.maint_notifications_pool_handler = MaintNotificationsPoolHandler(
|
|
389
|
-
self.connection_pool, maint_notifications_config
|
|
390
|
-
)
|
|
391
|
-
self.connection_pool.set_maint_notifications_pool_handler(
|
|
392
|
-
self.maint_notifications_pool_handler
|
|
393
|
-
)
|
|
394
|
-
else:
|
|
395
|
-
self.maint_notifications_pool_handler = None
|
|
396
|
-
|
|
397
406
|
self.single_connection_lock = threading.RLock()
|
|
398
407
|
self.connection = None
|
|
399
408
|
self._single_connection_client = single_connection_client
|
|
@@ -591,15 +600,9 @@ class Redis(RedisModuleCommands, CoreCommands, SentinelCommands):
|
|
|
591
600
|
return Monitor(self.connection_pool)
|
|
592
601
|
|
|
593
602
|
def client(self):
|
|
594
|
-
maint_notifications_config = (
|
|
595
|
-
None
|
|
596
|
-
if self.maint_notifications_pool_handler is None
|
|
597
|
-
else self.maint_notifications_pool_handler.config
|
|
598
|
-
)
|
|
599
603
|
return self.__class__(
|
|
600
604
|
connection_pool=self.connection_pool,
|
|
601
605
|
single_connection_client=True,
|
|
602
|
-
maint_notifications_config=maint_notifications_config,
|
|
603
606
|
)
|
|
604
607
|
|
|
605
608
|
def __enter__(self):
|
|
@@ -50,6 +50,7 @@ from redis.exceptions import (
|
|
|
50
50
|
WatchError,
|
|
51
51
|
)
|
|
52
52
|
from redis.lock import Lock
|
|
53
|
+
from redis.maint_notifications import MaintNotificationsConfig
|
|
53
54
|
from redis.retry import Retry
|
|
54
55
|
from redis.utils import (
|
|
55
56
|
deprecated_args,
|
|
@@ -1663,6 +1664,11 @@ class NodesManager:
|
|
|
1663
1664
|
backoff=NoBackoff(), retries=0, supported_errors=(ConnectionError,)
|
|
1664
1665
|
)
|
|
1665
1666
|
|
|
1667
|
+
protocol = kwargs.get("protocol", None)
|
|
1668
|
+
if protocol in [3, "3"]:
|
|
1669
|
+
kwargs.update(
|
|
1670
|
+
{"maint_notifications_config": MaintNotificationsConfig(enabled=False)}
|
|
1671
|
+
)
|
|
1666
1672
|
if self.from_url:
|
|
1667
1673
|
# Create a redis node with a costumed connection pool
|
|
1668
1674
|
kwargs.update({"host": host})
|
|
@@ -830,7 +830,7 @@ class ManagementCommands(CommandsProtocol):
|
|
|
830
830
|
|
|
831
831
|
return self.execute_command("COMMAND LIST", *pieces)
|
|
832
832
|
|
|
833
|
-
def command_getkeysandflags(self, *args:
|
|
833
|
+
def command_getkeysandflags(self, *args: str) -> List[Union[str, List[str]]]:
|
|
834
834
|
"""
|
|
835
835
|
Returns array of keys from a full Redis command and their usage flags.
|
|
836
836
|
|
|
@@ -848,7 +848,7 @@ class ManagementCommands(CommandsProtocol):
|
|
|
848
848
|
)
|
|
849
849
|
|
|
850
850
|
def config_get(
|
|
851
|
-
self, pattern: PatternT = "*", *args:
|
|
851
|
+
self, pattern: PatternT = "*", *args: PatternT, **kwargs
|
|
852
852
|
) -> ResponseT:
|
|
853
853
|
"""
|
|
854
854
|
Return a dictionary of configuration based on the ``pattern``
|
|
@@ -861,7 +861,7 @@ class ManagementCommands(CommandsProtocol):
|
|
|
861
861
|
self,
|
|
862
862
|
name: KeyT,
|
|
863
863
|
value: EncodableT,
|
|
864
|
-
*args:
|
|
864
|
+
*args: Union[KeyT, EncodableT],
|
|
865
865
|
**kwargs,
|
|
866
866
|
) -> ResponseT:
|
|
867
867
|
"""Set config item ``name`` with ``value``
|
|
@@ -987,9 +987,7 @@ class ManagementCommands(CommandsProtocol):
|
|
|
987
987
|
"""
|
|
988
988
|
return self.execute_command("SELECT", index, **kwargs)
|
|
989
989
|
|
|
990
|
-
def info(
|
|
991
|
-
self, section: Optional[str] = None, *args: List[str], **kwargs
|
|
992
|
-
) -> ResponseT:
|
|
990
|
+
def info(self, section: Optional[str] = None, *args: str, **kwargs) -> ResponseT:
|
|
993
991
|
"""
|
|
994
992
|
Returns a dictionary containing information about the Redis server
|
|
995
993
|
|
|
@@ -2606,7 +2604,7 @@ class ListCommands(CommandsProtocol):
|
|
|
2606
2604
|
self,
|
|
2607
2605
|
timeout: float,
|
|
2608
2606
|
numkeys: int,
|
|
2609
|
-
*args:
|
|
2607
|
+
*args: str,
|
|
2610
2608
|
direction: str,
|
|
2611
2609
|
count: Optional[int] = 1,
|
|
2612
2610
|
) -> Optional[list]:
|
|
@@ -2619,14 +2617,14 @@ class ListCommands(CommandsProtocol):
|
|
|
2619
2617
|
|
|
2620
2618
|
For more information, see https://redis.io/commands/blmpop
|
|
2621
2619
|
"""
|
|
2622
|
-
|
|
2620
|
+
cmd_args = [timeout, numkeys, *args, direction, "COUNT", count]
|
|
2623
2621
|
|
|
2624
|
-
return self.execute_command("BLMPOP", *
|
|
2622
|
+
return self.execute_command("BLMPOP", *cmd_args)
|
|
2625
2623
|
|
|
2626
2624
|
def lmpop(
|
|
2627
2625
|
self,
|
|
2628
2626
|
num_keys: int,
|
|
2629
|
-
*args:
|
|
2627
|
+
*args: str,
|
|
2630
2628
|
direction: str,
|
|
2631
2629
|
count: Optional[int] = 1,
|
|
2632
2630
|
) -> Union[Awaitable[list], list]:
|
|
@@ -2636,11 +2634,11 @@ class ListCommands(CommandsProtocol):
|
|
|
2636
2634
|
|
|
2637
2635
|
For more information, see https://redis.io/commands/lmpop
|
|
2638
2636
|
"""
|
|
2639
|
-
|
|
2637
|
+
cmd_args = [num_keys] + list(args) + [direction]
|
|
2640
2638
|
if count != 1:
|
|
2641
|
-
|
|
2639
|
+
cmd_args.extend(["COUNT", count])
|
|
2642
2640
|
|
|
2643
|
-
return self.execute_command("LMPOP", *
|
|
2641
|
+
return self.execute_command("LMPOP", *cmd_args)
|
|
2644
2642
|
|
|
2645
2643
|
def lindex(
|
|
2646
2644
|
self, name: str, index: int
|
|
@@ -4778,6 +4776,7 @@ class SortedSetCommands(CommandsProtocol):
|
|
|
4778
4776
|
name: KeyT,
|
|
4779
4777
|
value: EncodableT,
|
|
4780
4778
|
withscore: bool = False,
|
|
4779
|
+
score_cast_func: Union[type, Callable] = float,
|
|
4781
4780
|
) -> ResponseT:
|
|
4782
4781
|
"""
|
|
4783
4782
|
Returns a 0-based value indicating the rank of ``value`` in sorted set
|
|
@@ -4785,11 +4784,17 @@ class SortedSetCommands(CommandsProtocol):
|
|
|
4785
4784
|
The optional WITHSCORE argument supplements the command's
|
|
4786
4785
|
reply with the score of the element returned.
|
|
4787
4786
|
|
|
4787
|
+
``score_cast_func`` a callable used to cast the score return value
|
|
4788
|
+
|
|
4788
4789
|
For more information, see https://redis.io/commands/zrank
|
|
4789
4790
|
"""
|
|
4791
|
+
pieces = ["ZRANK", name, value]
|
|
4790
4792
|
if withscore:
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
+
pieces.append("WITHSCORE")
|
|
4794
|
+
|
|
4795
|
+
options = {"withscore": withscore, "score_cast_func": score_cast_func}
|
|
4796
|
+
|
|
4797
|
+
return self.execute_command(*pieces, **options)
|
|
4793
4798
|
|
|
4794
4799
|
def zrem(self, name: KeyT, *values: FieldT) -> ResponseT:
|
|
4795
4800
|
"""
|
|
@@ -4837,6 +4842,7 @@ class SortedSetCommands(CommandsProtocol):
|
|
|
4837
4842
|
name: KeyT,
|
|
4838
4843
|
value: EncodableT,
|
|
4839
4844
|
withscore: bool = False,
|
|
4845
|
+
score_cast_func: Union[type, Callable] = float,
|
|
4840
4846
|
) -> ResponseT:
|
|
4841
4847
|
"""
|
|
4842
4848
|
Returns a 0-based value indicating the descending rank of
|
|
@@ -4844,13 +4850,17 @@ class SortedSetCommands(CommandsProtocol):
|
|
|
4844
4850
|
The optional ``withscore`` argument supplements the command's
|
|
4845
4851
|
reply with the score of the element returned.
|
|
4846
4852
|
|
|
4853
|
+
``score_cast_func`` a callable used to cast the score return value
|
|
4854
|
+
|
|
4847
4855
|
For more information, see https://redis.io/commands/zrevrank
|
|
4848
4856
|
"""
|
|
4857
|
+
pieces = ["ZREVRANK", name, value]
|
|
4849
4858
|
if withscore:
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4859
|
+
pieces.append("WITHSCORE")
|
|
4860
|
+
|
|
4861
|
+
options = {"withscore": withscore, "score_cast_func": score_cast_func}
|
|
4862
|
+
|
|
4863
|
+
return self.execute_command(*pieces, **options)
|
|
4854
4864
|
|
|
4855
4865
|
def zscore(self, name: KeyT, value: EncodableT) -> ResponseT:
|
|
4856
4866
|
"""
|
|
@@ -4865,6 +4875,7 @@ class SortedSetCommands(CommandsProtocol):
|
|
|
4865
4875
|
keys: Union[Sequence[KeyT], Mapping[AnyKeyT, float]],
|
|
4866
4876
|
aggregate: Optional[str] = None,
|
|
4867
4877
|
withscores: bool = False,
|
|
4878
|
+
score_cast_func: Union[type, Callable] = float,
|
|
4868
4879
|
) -> ResponseT:
|
|
4869
4880
|
"""
|
|
4870
4881
|
Return the union of multiple sorted sets specified by ``keys``.
|
|
@@ -4872,9 +4883,18 @@ class SortedSetCommands(CommandsProtocol):
|
|
|
4872
4883
|
Scores will be aggregated based on the ``aggregate``, or SUM if
|
|
4873
4884
|
none is provided.
|
|
4874
4885
|
|
|
4886
|
+
``score_cast_func`` a callable used to cast the score return value
|
|
4887
|
+
|
|
4875
4888
|
For more information, see https://redis.io/commands/zunion
|
|
4876
4889
|
"""
|
|
4877
|
-
return self._zaggregate(
|
|
4890
|
+
return self._zaggregate(
|
|
4891
|
+
"ZUNION",
|
|
4892
|
+
None,
|
|
4893
|
+
keys,
|
|
4894
|
+
aggregate,
|
|
4895
|
+
withscores=withscores,
|
|
4896
|
+
score_cast_func=score_cast_func,
|
|
4897
|
+
)
|
|
4878
4898
|
|
|
4879
4899
|
def zunionstore(
|
|
4880
4900
|
self,
|
|
@@ -5863,12 +5883,16 @@ class ScriptCommands(CommandsProtocol):
|
|
|
5863
5883
|
"""
|
|
5864
5884
|
|
|
5865
5885
|
def _eval(
|
|
5866
|
-
self,
|
|
5886
|
+
self,
|
|
5887
|
+
command: str,
|
|
5888
|
+
script: str,
|
|
5889
|
+
numkeys: int,
|
|
5890
|
+
*keys_and_args: Union[KeyT, EncodableT],
|
|
5867
5891
|
) -> Union[Awaitable[str], str]:
|
|
5868
5892
|
return self.execute_command(command, script, numkeys, *keys_and_args)
|
|
5869
5893
|
|
|
5870
5894
|
def eval(
|
|
5871
|
-
self, script: str, numkeys: int, *keys_and_args:
|
|
5895
|
+
self, script: str, numkeys: int, *keys_and_args: Union[KeyT, EncodableT]
|
|
5872
5896
|
) -> Union[Awaitable[str], str]:
|
|
5873
5897
|
"""
|
|
5874
5898
|
Execute the Lua ``script``, specifying the ``numkeys`` the script
|
|
@@ -5883,7 +5907,7 @@ class ScriptCommands(CommandsProtocol):
|
|
|
5883
5907
|
return self._eval("EVAL", script, numkeys, *keys_and_args)
|
|
5884
5908
|
|
|
5885
5909
|
def eval_ro(
|
|
5886
|
-
self, script: str, numkeys: int, *keys_and_args:
|
|
5910
|
+
self, script: str, numkeys: int, *keys_and_args: Union[KeyT, EncodableT]
|
|
5887
5911
|
) -> Union[Awaitable[str], str]:
|
|
5888
5912
|
"""
|
|
5889
5913
|
The read-only variant of the EVAL command
|
|
@@ -5897,12 +5921,16 @@ class ScriptCommands(CommandsProtocol):
|
|
|
5897
5921
|
return self._eval("EVAL_RO", script, numkeys, *keys_and_args)
|
|
5898
5922
|
|
|
5899
5923
|
def _evalsha(
|
|
5900
|
-
self,
|
|
5924
|
+
self,
|
|
5925
|
+
command: str,
|
|
5926
|
+
sha: str,
|
|
5927
|
+
numkeys: int,
|
|
5928
|
+
*keys_and_args: Union[KeyT, EncodableT],
|
|
5901
5929
|
) -> Union[Awaitable[str], str]:
|
|
5902
5930
|
return self.execute_command(command, sha, numkeys, *keys_and_args)
|
|
5903
5931
|
|
|
5904
5932
|
def evalsha(
|
|
5905
|
-
self, sha: str, numkeys: int, *keys_and_args:
|
|
5933
|
+
self, sha: str, numkeys: int, *keys_and_args: Union[KeyT, EncodableT]
|
|
5906
5934
|
) -> Union[Awaitable[str], str]:
|
|
5907
5935
|
"""
|
|
5908
5936
|
Use the ``sha`` to execute a Lua script already registered via EVAL
|
|
@@ -5918,7 +5946,7 @@ class ScriptCommands(CommandsProtocol):
|
|
|
5918
5946
|
return self._evalsha("EVALSHA", sha, numkeys, *keys_and_args)
|
|
5919
5947
|
|
|
5920
5948
|
def evalsha_ro(
|
|
5921
|
-
self, sha: str, numkeys: int, *keys_and_args:
|
|
5949
|
+
self, sha: str, numkeys: int, *keys_and_args: Union[KeyT, EncodableT]
|
|
5922
5950
|
) -> Union[Awaitable[str], str]:
|
|
5923
5951
|
"""
|
|
5924
5952
|
The read-only variant of the EVALSHA command
|