valkey-glide 2.0.0rc5__cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl → 2.0.0rc6__cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
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.
Potentially problematic release.
This version of valkey-glide might be problematic. Click here for more details.
- glide/async_commands/batch.py +40 -24
- glide/async_commands/cluster_commands.py +7 -1
- glide/async_commands/core.py +25 -20
- glide/async_commands/standalone_commands.py +8 -1
- glide/glide.cpython-312-aarch64-linux-gnu.so +0 -0
- glide/glide_client.py +191 -85
- glide/routes.py +25 -0
- {valkey_glide-2.0.0rc5.dist-info → valkey_glide-2.0.0rc6.dist-info}/METADATA +21 -4
- {valkey_glide-2.0.0rc5.dist-info → valkey_glide-2.0.0rc6.dist-info}/RECORD +10 -10
- {valkey_glide-2.0.0rc5.dist-info → valkey_glide-2.0.0rc6.dist-info}/WHEEL +0 -0
glide/async_commands/batch.py
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
|
|
2
2
|
|
|
3
|
+
import sys
|
|
3
4
|
import threading
|
|
4
5
|
from typing import List, Mapping, Optional, Tuple, TypeVar, Union
|
|
5
6
|
|
|
6
|
-
from deprecated import deprecated
|
|
7
7
|
from glide.async_commands.bitmap import (
|
|
8
8
|
BitFieldGet,
|
|
9
9
|
BitFieldSubCommands,
|
|
@@ -55,8 +55,14 @@ from glide.async_commands.stream import (
|
|
|
55
55
|
_create_xpending_range_args,
|
|
56
56
|
)
|
|
57
57
|
from glide.constants import TEncodable
|
|
58
|
+
from glide.exceptions import RequestError
|
|
58
59
|
from glide.protobuf.command_request_pb2 import RequestType
|
|
59
60
|
|
|
61
|
+
if sys.version_info >= (3, 13):
|
|
62
|
+
from warnings import deprecated
|
|
63
|
+
else:
|
|
64
|
+
from typing_extensions import deprecated
|
|
65
|
+
|
|
60
66
|
TBatch = TypeVar("TBatch", bound="BaseBatch")
|
|
61
67
|
|
|
62
68
|
|
|
@@ -109,7 +115,7 @@ class BaseBatch:
|
|
|
109
115
|
|
|
110
116
|
def get(self: TBatch, key: TEncodable) -> TBatch:
|
|
111
117
|
"""
|
|
112
|
-
Get the value associated with the given key, or null if no such
|
|
118
|
+
Get the value associated with the given key, or null if no such key exists.
|
|
113
119
|
|
|
114
120
|
See [valkey.io](https://valkey.io/commands/get/) for details.
|
|
115
121
|
|
|
@@ -273,6 +279,10 @@ class BaseBatch:
|
|
|
273
279
|
[custom command](https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#custom-command)
|
|
274
280
|
for details on the restrictions and limitations of the custom command API.
|
|
275
281
|
|
|
282
|
+
This function should only be used for single-response commands. Commands that don't return complete response and awaits
|
|
283
|
+
(such as SUBSCRIBE), or that return potentially more than a single response (such as XREAD), or that change the
|
|
284
|
+
client's behavior (such as entering pub/sub mode on RESP2 connections) shouldn't be called using this function.
|
|
285
|
+
|
|
276
286
|
Args:
|
|
277
287
|
command_args (List[TEncodable]): List of command arguments.
|
|
278
288
|
Every part of the command, including the command name and subcommands, should be added as a
|
|
@@ -312,6 +322,8 @@ class BaseBatch:
|
|
|
312
322
|
"""
|
|
313
323
|
Get information and statistics about the server.
|
|
314
324
|
|
|
325
|
+
Starting from server version 7, command supports multiple section arguments.
|
|
326
|
+
|
|
315
327
|
See [valkey.io](https://valkey.io/commands/info/) for details.
|
|
316
328
|
|
|
317
329
|
Args:
|
|
@@ -1057,7 +1069,7 @@ class BaseBatch:
|
|
|
1057
1069
|
Command response:
|
|
1058
1070
|
Optional[Mapping[bytes, List[bytes]]]: A map of `key` name mapped to an array of popped elements.
|
|
1059
1071
|
|
|
1060
|
-
None if no elements could be popped.
|
|
1072
|
+
`None` if no elements could be popped.
|
|
1061
1073
|
|
|
1062
1074
|
Since: Valkey version 7.0.0.
|
|
1063
1075
|
"""
|
|
@@ -2306,6 +2318,10 @@ class BaseBatch:
|
|
|
2306
2318
|
args.append("REPLACE")
|
|
2307
2319
|
if absttl is True:
|
|
2308
2320
|
args.append("ABSTTL")
|
|
2321
|
+
if idletime is not None and frequency is not None:
|
|
2322
|
+
raise RequestError(
|
|
2323
|
+
"syntax error: IDLETIME and FREQ cannot be set at the same time."
|
|
2324
|
+
)
|
|
2309
2325
|
if idletime is not None:
|
|
2310
2326
|
args.extend(["IDLETIME", str(idletime)])
|
|
2311
2327
|
if frequency is not None:
|
|
@@ -2412,26 +2428,26 @@ class BaseBatch:
|
|
|
2412
2428
|
|
|
2413
2429
|
Args:
|
|
2414
2430
|
key (TEncodable): The key of the stream.
|
|
2415
|
-
start (StreamRangeBound): The starting stream ID bound for the range.
|
|
2431
|
+
start (StreamRangeBound): The starting stream entry ID bound for the range.
|
|
2416
2432
|
|
|
2417
|
-
- Use `IdBound` to specify a stream ID.
|
|
2418
|
-
-
|
|
2433
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
2434
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
2419
2435
|
- Use `MinId` to start with the minimum available ID.
|
|
2420
2436
|
|
|
2421
|
-
end (StreamRangeBound): The ending stream ID bound for the range.
|
|
2437
|
+
end (StreamRangeBound): The ending stream entry ID bound for the range.
|
|
2422
2438
|
|
|
2423
|
-
- Use `IdBound` to specify a stream ID.
|
|
2424
|
-
-
|
|
2439
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
2440
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
2425
2441
|
- Use `MaxId` to end with the maximum available ID.
|
|
2426
2442
|
|
|
2427
2443
|
count (Optional[int]): An optional argument specifying the maximum count of stream entries to return.
|
|
2428
2444
|
If `count` is not provided, all stream entries in the range will be returned.
|
|
2429
2445
|
|
|
2430
2446
|
Command response:
|
|
2431
|
-
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream IDs to stream entry data, where entry data is a
|
|
2447
|
+
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream entry IDs to stream entry data, where entry data is a
|
|
2432
2448
|
list of pairings with format `[[field, entry], [field, entry], ...]`.
|
|
2433
2449
|
|
|
2434
|
-
Returns None if the range arguments are not applicable.
|
|
2450
|
+
Returns None if the range arguments are not applicable. Or if count is non-positive.
|
|
2435
2451
|
"""
|
|
2436
2452
|
args = [key, start.to_arg(), end.to_arg()]
|
|
2437
2453
|
if count is not None:
|
|
@@ -2454,26 +2470,26 @@ class BaseBatch:
|
|
|
2454
2470
|
|
|
2455
2471
|
Args:
|
|
2456
2472
|
key (TEncodable): The key of the stream.
|
|
2457
|
-
end (StreamRangeBound): The ending stream ID bound for the range.
|
|
2473
|
+
end (StreamRangeBound): The ending stream entry ID bound for the range.
|
|
2458
2474
|
|
|
2459
|
-
- Use `IdBound` to specify a stream ID.
|
|
2460
|
-
-
|
|
2475
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
2476
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
2461
2477
|
- Use `MaxId` to end with the maximum available ID.
|
|
2462
2478
|
|
|
2463
|
-
start (StreamRangeBound): The starting stream ID bound for the range.
|
|
2479
|
+
start (StreamRangeBound): The starting stream entry ID bound for the range.
|
|
2464
2480
|
|
|
2465
|
-
- Use `IdBound` to specify a stream ID.
|
|
2466
|
-
-
|
|
2481
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
2482
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
2467
2483
|
- Use `MinId` to start with the minimum available ID.
|
|
2468
2484
|
|
|
2469
2485
|
count (Optional[int]): An optional argument specifying the maximum count of stream entries to return.
|
|
2470
2486
|
If `count` is not provided, all stream entries in the range will be returned.
|
|
2471
2487
|
|
|
2472
2488
|
Command response:
|
|
2473
|
-
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream IDs to stream entry data, where entry data is a
|
|
2489
|
+
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream entry IDs to stream entry data, where entry data is a
|
|
2474
2490
|
list of pairings with format `[[field, entry], [field, entry], ...]`.
|
|
2475
2491
|
|
|
2476
|
-
Returns None if the range arguments are not applicable.
|
|
2492
|
+
Returns None if the range arguments are not applicable. Or if count is non-positive.
|
|
2477
2493
|
"""
|
|
2478
2494
|
args = [key, end.to_arg(), start.to_arg()]
|
|
2479
2495
|
if count is not None:
|
|
@@ -2787,7 +2803,7 @@ class BaseBatch:
|
|
|
2787
2803
|
min_idle_time_ms (int): Filters the claimed entries to those that have been idle for more than the specified
|
|
2788
2804
|
value.
|
|
2789
2805
|
start (TEncodable): Filters the claimed entries to those that have an ID equal or greater than the specified value.
|
|
2790
|
-
count (Optional[int]): Limits the number of claimed entries to the specified value.
|
|
2806
|
+
count (Optional[int]): Limits the number of claimed entries to the specified value. Default value is 100.
|
|
2791
2807
|
|
|
2792
2808
|
Command response:
|
|
2793
2809
|
List[Union[str, Mapping[bytes, List[List[bytes]]], List[bytes]]]: A list containing the following elements:
|
|
@@ -2832,7 +2848,7 @@ class BaseBatch:
|
|
|
2832
2848
|
min_idle_time_ms (int): Filters the claimed entries to those that have been idle for more than the specified
|
|
2833
2849
|
value.
|
|
2834
2850
|
start (TEncodable): Filters the claimed entries to those that have an ID equal or greater than the specified value.
|
|
2835
|
-
count (Optional[int]): Limits the number of claimed entries to the specified value.
|
|
2851
|
+
count (Optional[int]): Limits the number of claimed entries to the specified value. Default value is 100.
|
|
2836
2852
|
|
|
2837
2853
|
Command response:
|
|
2838
2854
|
List[Union[bytes, List[bytes]]]: A list containing the following elements:
|
|
@@ -3263,7 +3279,7 @@ class BaseBatch:
|
|
|
3263
3279
|
Commands response:
|
|
3264
3280
|
Optional[float]: The score of the member.
|
|
3265
3281
|
|
|
3266
|
-
If there was a conflict with choosing the XX/NX/LT/GT options, the operation aborts and None is returned.
|
|
3282
|
+
If there was a conflict with choosing the XX/NX/LT/GT options, the operation aborts and `None` is returned.
|
|
3267
3283
|
"""
|
|
3268
3284
|
args = [key]
|
|
3269
3285
|
if existing_options:
|
|
@@ -5573,13 +5589,13 @@ class ClusterBatch(BaseBatch):
|
|
|
5573
5589
|
# TODO: add all CLUSTER commands
|
|
5574
5590
|
|
|
5575
5591
|
|
|
5576
|
-
@deprecated(
|
|
5592
|
+
@deprecated("Use ClusterBatch(is_atomic=True) instead.")
|
|
5577
5593
|
class Transaction(Batch):
|
|
5578
5594
|
def __init__(self):
|
|
5579
5595
|
super().__init__(is_atomic=True)
|
|
5580
5596
|
|
|
5581
5597
|
|
|
5582
|
-
@deprecated(
|
|
5598
|
+
@deprecated("Use ClusterBatch(is_atomic=True) instead.")
|
|
5583
5599
|
class ClusterTransaction(ClusterBatch):
|
|
5584
5600
|
def __init__(self):
|
|
5585
5601
|
super().__init__(is_atomic=True)
|
|
@@ -36,9 +36,13 @@ class ClusterCommands(CoreCommands):
|
|
|
36
36
|
See the [Valkey GLIDE Wiki](https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#custom-command)
|
|
37
37
|
for details on the restrictions and limitations of the custom command API.
|
|
38
38
|
|
|
39
|
+
This function should only be used for single-response commands. Commands that don't return complete response and awaits
|
|
40
|
+
(such as SUBSCRIBE), or that return potentially more than a single response (such as XREAD), or that change the
|
|
41
|
+
client's behavior (such as entering pub/sub mode on RESP2 connections) shouldn't be called using this function.
|
|
42
|
+
|
|
39
43
|
For example - Return a list of all pub/sub clients from all nodes::
|
|
40
44
|
|
|
41
|
-
|
|
45
|
+
await client.customCommand(["CLIENT", "LIST","TYPE", "PUBSUB"], AllNodes())
|
|
42
46
|
|
|
43
47
|
Args:
|
|
44
48
|
command_args (List[TEncodable]): List of the command's arguments, where each argument is either a string or bytes.
|
|
@@ -63,6 +67,8 @@ class ClusterCommands(CoreCommands):
|
|
|
63
67
|
"""
|
|
64
68
|
Get information and statistics about the server.
|
|
65
69
|
|
|
70
|
+
Starting from server version 7, command supports multiple section arguments.
|
|
71
|
+
|
|
66
72
|
See [valkey.io](https://valkey.io/commands/info/) for details.
|
|
67
73
|
|
|
68
74
|
Args:
|
glide/async_commands/core.py
CHANGED
|
@@ -61,6 +61,7 @@ from glide.constants import (
|
|
|
61
61
|
TXInfoStreamFullResponse,
|
|
62
62
|
TXInfoStreamResponse,
|
|
63
63
|
)
|
|
64
|
+
from glide.exceptions import RequestError
|
|
64
65
|
from glide.protobuf.command_request_pb2 import RequestType
|
|
65
66
|
from glide.routes import Route
|
|
66
67
|
|
|
@@ -593,7 +594,7 @@ class CoreCommands(Protocol):
|
|
|
593
594
|
|
|
594
595
|
async def get(self, key: TEncodable) -> Optional[bytes]:
|
|
595
596
|
"""
|
|
596
|
-
Get the value associated with the given key, or null if no such
|
|
597
|
+
Get the value associated with the given key, or null if no such key exists.
|
|
597
598
|
|
|
598
599
|
See [valkey.io](https://valkey.io/commands/get/) for details.
|
|
599
600
|
|
|
@@ -3114,26 +3115,26 @@ class CoreCommands(Protocol):
|
|
|
3114
3115
|
|
|
3115
3116
|
Args:
|
|
3116
3117
|
key (TEncodable): The key of the stream.
|
|
3117
|
-
start (StreamRangeBound): The starting stream ID bound for the range.
|
|
3118
|
+
start (StreamRangeBound): The starting stream entry ID bound for the range.
|
|
3118
3119
|
|
|
3119
|
-
- Use `IdBound` to specify a stream ID.
|
|
3120
|
-
-
|
|
3120
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
3121
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
3121
3122
|
- Use `MinId` to start with the minimum available ID.
|
|
3122
3123
|
|
|
3123
|
-
end (StreamRangeBound): The ending stream ID bound for the range.
|
|
3124
|
+
end (StreamRangeBound): The ending stream entry ID bound for the range.
|
|
3124
3125
|
|
|
3125
|
-
- Use `IdBound` to specify a stream ID.
|
|
3126
|
-
-
|
|
3126
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
3127
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
3127
3128
|
- Use `MaxId` to end with the maximum available ID.
|
|
3128
3129
|
|
|
3129
3130
|
count (Optional[int]): An optional argument specifying the maximum count of stream entries to return.
|
|
3130
3131
|
If `count` is not provided, all stream entries in the range will be returned.
|
|
3131
3132
|
|
|
3132
3133
|
Returns:
|
|
3133
|
-
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream IDs to stream entry data, where entry data is a
|
|
3134
|
+
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream entry IDs to stream entry data, where entry data is a
|
|
3134
3135
|
list of pairings with format `[[field, entry], [field, entry], ...]`.
|
|
3135
3136
|
|
|
3136
|
-
Returns None if the range arguments are not applicable.
|
|
3137
|
+
Returns None if the range arguments are not applicable. Or if count is non-positive.
|
|
3137
3138
|
|
|
3138
3139
|
Examples:
|
|
3139
3140
|
>>> await client.xadd("mystream", [("field1", "value1")], StreamAddOptions(id="0-1"))
|
|
@@ -3168,26 +3169,26 @@ class CoreCommands(Protocol):
|
|
|
3168
3169
|
|
|
3169
3170
|
Args:
|
|
3170
3171
|
key (TEncodable): The key of the stream.
|
|
3171
|
-
end (StreamRangeBound): The ending stream ID bound for the range.
|
|
3172
|
+
end (StreamRangeBound): The ending stream entry ID bound for the range.
|
|
3172
3173
|
|
|
3173
|
-
- Use `IdBound` to specify a stream ID.
|
|
3174
|
-
-
|
|
3174
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
3175
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
3175
3176
|
- Use `MaxId` to end with the maximum available ID.
|
|
3176
3177
|
|
|
3177
|
-
start (StreamRangeBound): The starting stream ID bound for the range.
|
|
3178
|
+
start (StreamRangeBound): The starting stream entry ID bound for the range.
|
|
3178
3179
|
|
|
3179
|
-
- Use `IdBound` to specify a stream ID.
|
|
3180
|
-
-
|
|
3180
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
3181
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
3181
3182
|
- Use `MinId` to start with the minimum available ID.
|
|
3182
3183
|
|
|
3183
3184
|
count (Optional[int]): An optional argument specifying the maximum count of stream entries to return.
|
|
3184
3185
|
If `count` is not provided, all stream entries in the range will be returned.
|
|
3185
3186
|
|
|
3186
3187
|
Returns:
|
|
3187
|
-
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream IDs to stream entry data, where entry data is a
|
|
3188
|
+
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream entry IDs to stream entry data, where entry data is a
|
|
3188
3189
|
list of pairings with format `[[field, entry], [field, entry], ...]`.
|
|
3189
3190
|
|
|
3190
|
-
Returns None if the range arguments are not applicable.
|
|
3191
|
+
Returns None if the range arguments are not applicable. Or if count is non-positive.
|
|
3191
3192
|
|
|
3192
3193
|
Examples:
|
|
3193
3194
|
>>> await client.xadd("mystream", [("field1", "value1")], StreamAddOptions(id="0-1"))
|
|
@@ -3273,7 +3274,7 @@ class CoreCommands(Protocol):
|
|
|
3273
3274
|
key (TEncodable): The key of the stream.
|
|
3274
3275
|
group_name (TEncodable): The newly created consumer group name.
|
|
3275
3276
|
group_id (TEncodable): The stream entry ID that specifies the last delivered entry in the stream from the new
|
|
3276
|
-
group
|
|
3277
|
+
group's perspective. The special ID "$" can be used to specify the last entry in the stream.
|
|
3277
3278
|
options (Optional[StreamGroupOptions]): Options for creating the stream group.
|
|
3278
3279
|
|
|
3279
3280
|
Returns:
|
|
@@ -3733,7 +3734,7 @@ class CoreCommands(Protocol):
|
|
|
3733
3734
|
min_idle_time_ms (int): Filters the claimed entries to those that have been idle for more than the specified
|
|
3734
3735
|
value.
|
|
3735
3736
|
start (TEncodable): Filters the claimed entries to those that have an ID equal or greater than the specified value.
|
|
3736
|
-
count (Optional[int]): Limits the number of claimed entries to the specified value.
|
|
3737
|
+
count (Optional[int]): Limits the number of claimed entries to the specified value. Default value is 100.
|
|
3737
3738
|
|
|
3738
3739
|
Returns:
|
|
3739
3740
|
List[Union[bytes, Mapping[bytes, List[List[bytes]]], List[bytes]]]: A list containing the following elements:
|
|
@@ -3820,7 +3821,7 @@ class CoreCommands(Protocol):
|
|
|
3820
3821
|
min_idle_time_ms (int): Filters the claimed entries to those that have been idle for more than the specified
|
|
3821
3822
|
value.
|
|
3822
3823
|
start (TEncodable): Filters the claimed entries to those that have an ID equal or greater than the specified value.
|
|
3823
|
-
count (Optional[int]): Limits the number of claimed entries to the specified value.
|
|
3824
|
+
count (Optional[int]): Limits the number of claimed entries to the specified value. Default value is 100.
|
|
3824
3825
|
|
|
3825
3826
|
Returns:
|
|
3826
3827
|
List[Union[bytes, List[bytes]]]: A list containing the following elements:
|
|
@@ -6649,6 +6650,10 @@ class CoreCommands(Protocol):
|
|
|
6649
6650
|
args.append("REPLACE")
|
|
6650
6651
|
if absttl is True:
|
|
6651
6652
|
args.append("ABSTTL")
|
|
6653
|
+
if idletime is not None and frequency is not None:
|
|
6654
|
+
raise RequestError(
|
|
6655
|
+
"syntax error: IDLETIME and FREQ cannot be set at the same time."
|
|
6656
|
+
)
|
|
6652
6657
|
if idletime is not None:
|
|
6653
6658
|
args.extend(["IDLETIME", str(idletime)])
|
|
6654
6659
|
if frequency is not None:
|
|
@@ -31,6 +31,10 @@ class StandaloneCommands(CoreCommands):
|
|
|
31
31
|
See the [Valkey GLIDE Wiki](https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#custom-command)
|
|
32
32
|
for details on the restrictions and limitations of the custom command API.
|
|
33
33
|
|
|
34
|
+
This function should only be used for single-response commands. Commands that don't return complete response and awaits
|
|
35
|
+
(such as SUBSCRIBE), or that return potentially more than a single response (such as XREAD), or that change the
|
|
36
|
+
client's behavior (such as entering pub/sub mode on RESP2 connections) shouldn't be called using this function.
|
|
37
|
+
|
|
34
38
|
Args:
|
|
35
39
|
command_args (List[TEncodable]): List of the command's arguments, where each argument is either a string or bytes.
|
|
36
40
|
Every part of the command, including the command name and subcommands, should be added as a separate value in args.
|
|
@@ -39,7 +43,8 @@ class StandaloneCommands(CoreCommands):
|
|
|
39
43
|
TResult: The returning value depends on the executed command.
|
|
40
44
|
|
|
41
45
|
Example:
|
|
42
|
-
>>>
|
|
46
|
+
>>> await client.customCommand(["CLIENT", "LIST", "TYPE", "PUBSUB"])
|
|
47
|
+
# Expected Output: A list of all pub/sub clients
|
|
43
48
|
|
|
44
49
|
"""
|
|
45
50
|
return await self._execute_command(RequestType.CustomCommand, command_args)
|
|
@@ -51,6 +56,8 @@ class StandaloneCommands(CoreCommands):
|
|
|
51
56
|
"""
|
|
52
57
|
Get information and statistics about the server.
|
|
53
58
|
|
|
59
|
+
Starting from server version 7, command supports multiple section arguments.
|
|
60
|
+
|
|
54
61
|
See [valkey.io](https://valkey.io/commands/info/) for details.
|
|
55
62
|
|
|
56
63
|
Args:
|
|
Binary file
|
glide/glide_client.py
CHANGED
|
@@ -1,9 +1,24 @@
|
|
|
1
1
|
# Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0
|
|
2
2
|
|
|
3
|
-
import asyncio
|
|
4
3
|
import sys
|
|
5
4
|
import threading
|
|
6
|
-
from typing import
|
|
5
|
+
from typing import (
|
|
6
|
+
TYPE_CHECKING,
|
|
7
|
+
Any,
|
|
8
|
+
Awaitable,
|
|
9
|
+
Dict,
|
|
10
|
+
List,
|
|
11
|
+
Optional,
|
|
12
|
+
Set,
|
|
13
|
+
Tuple,
|
|
14
|
+
Type,
|
|
15
|
+
Union,
|
|
16
|
+
cast,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
import anyio
|
|
20
|
+
import sniffio
|
|
21
|
+
from anyio import to_thread
|
|
7
22
|
|
|
8
23
|
from glide.async_commands.cluster_commands import ClusterCommands
|
|
9
24
|
from glide.async_commands.command_args import ObjectType
|
|
@@ -38,12 +53,18 @@ from .glide import (
|
|
|
38
53
|
)
|
|
39
54
|
|
|
40
55
|
if sys.version_info >= (3, 11):
|
|
41
|
-
import asyncio as async_timeout
|
|
42
56
|
from typing import Self
|
|
43
57
|
else:
|
|
44
|
-
import async_timeout
|
|
45
58
|
from typing_extensions import Self
|
|
46
59
|
|
|
60
|
+
if TYPE_CHECKING:
|
|
61
|
+
import asyncio
|
|
62
|
+
|
|
63
|
+
import trio
|
|
64
|
+
|
|
65
|
+
TTask = Union[asyncio.Task[None], trio.lowlevel.Task]
|
|
66
|
+
TFuture = Union[asyncio.Future[Any], "_CompatFuture"]
|
|
67
|
+
|
|
47
68
|
|
|
48
69
|
def get_request_error_class(
|
|
49
70
|
error_type: Optional[RequestErrorType.ValueType],
|
|
@@ -59,23 +80,94 @@ def get_request_error_class(
|
|
|
59
80
|
return RequestError
|
|
60
81
|
|
|
61
82
|
|
|
83
|
+
class _CompatFuture:
|
|
84
|
+
"""anyio shim for asyncio.Future-like functionality"""
|
|
85
|
+
|
|
86
|
+
def __init__(self) -> None:
|
|
87
|
+
self._is_done = anyio.Event()
|
|
88
|
+
self._result: Any = None
|
|
89
|
+
self._exception: Optional[Exception] = None
|
|
90
|
+
|
|
91
|
+
def set_result(self, result: Any) -> None:
|
|
92
|
+
self._result = result
|
|
93
|
+
self._is_done.set()
|
|
94
|
+
|
|
95
|
+
def set_exception(self, exception: Exception) -> None:
|
|
96
|
+
self._exception = exception
|
|
97
|
+
self._is_done.set()
|
|
98
|
+
|
|
99
|
+
def done(self) -> bool:
|
|
100
|
+
return self._is_done.is_set()
|
|
101
|
+
|
|
102
|
+
def __await__(self):
|
|
103
|
+
return self._is_done.wait().__await__()
|
|
104
|
+
|
|
105
|
+
def result(self) -> Any:
|
|
106
|
+
if self._exception:
|
|
107
|
+
raise self._exception
|
|
108
|
+
|
|
109
|
+
return self._result
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _get_new_future_instance() -> "TFuture":
|
|
113
|
+
if sniffio.current_async_library() == "asyncio":
|
|
114
|
+
import asyncio
|
|
115
|
+
|
|
116
|
+
return asyncio.get_running_loop().create_future()
|
|
117
|
+
|
|
118
|
+
# _CompatFuture is also compatible with asyncio, but is not as closely integrated
|
|
119
|
+
# into the asyncio event loop and thus introduces a noticeable performance
|
|
120
|
+
# degradation. so we only use it for trio
|
|
121
|
+
return _CompatFuture()
|
|
122
|
+
|
|
123
|
+
|
|
62
124
|
class BaseClient(CoreCommands):
|
|
63
125
|
def __init__(self, config: BaseClientConfiguration):
|
|
64
126
|
"""
|
|
65
127
|
To create a new client, use the `create` classmethod
|
|
66
128
|
"""
|
|
67
129
|
self.config: BaseClientConfiguration = config
|
|
68
|
-
self._available_futures: Dict[int,
|
|
130
|
+
self._available_futures: Dict[int, "TFuture"] = {}
|
|
69
131
|
self._available_callback_indexes: List[int] = list()
|
|
70
132
|
self._buffered_requests: List[TRequest] = list()
|
|
71
133
|
self._writer_lock = threading.Lock()
|
|
72
134
|
self.socket_path: Optional[str] = None
|
|
73
|
-
self._reader_task: Optional[
|
|
135
|
+
self._reader_task: Optional["TTask"] = None
|
|
74
136
|
self._is_closed: bool = False
|
|
75
|
-
self._pubsub_futures: List[
|
|
137
|
+
self._pubsub_futures: List["TFuture"] = []
|
|
76
138
|
self._pubsub_lock = threading.Lock()
|
|
77
139
|
self._pending_push_notifications: List[Response] = list()
|
|
78
140
|
|
|
141
|
+
self._pending_tasks: Optional[Set[Awaitable[None]]] = None
|
|
142
|
+
"""asyncio-only to avoid gc on pending write tasks"""
|
|
143
|
+
|
|
144
|
+
def _create_task(self, task, *args, **kwargs):
|
|
145
|
+
"""framework agnostic free-floating task shim"""
|
|
146
|
+
framework = sniffio.current_async_library()
|
|
147
|
+
if framework == "trio":
|
|
148
|
+
from functools import partial
|
|
149
|
+
|
|
150
|
+
import trio
|
|
151
|
+
|
|
152
|
+
return trio.lowlevel.spawn_system_task(partial(task, **kwargs), *args)
|
|
153
|
+
elif framework == "asyncio":
|
|
154
|
+
import asyncio
|
|
155
|
+
|
|
156
|
+
# the asyncio event loop holds weak refs to tasks, so it's recommended to
|
|
157
|
+
# hold strong refs to them during their lifetime to prevent garbage
|
|
158
|
+
# collection
|
|
159
|
+
t = asyncio.create_task(task(*args, **kwargs))
|
|
160
|
+
|
|
161
|
+
if self._pending_tasks is None:
|
|
162
|
+
self._pending_tasks = set()
|
|
163
|
+
|
|
164
|
+
self._pending_tasks.add(t)
|
|
165
|
+
t.add_done_callback(self._pending_tasks.discard)
|
|
166
|
+
|
|
167
|
+
return t
|
|
168
|
+
|
|
169
|
+
raise RuntimeError(f"Unsupported async framework {framework}")
|
|
170
|
+
|
|
79
171
|
@classmethod
|
|
80
172
|
async def create(cls, config: BaseClientConfiguration) -> Self:
|
|
81
173
|
"""Creates a Glide client.
|
|
@@ -148,8 +240,8 @@ class BaseClient(CoreCommands):
|
|
|
148
240
|
"""
|
|
149
241
|
config = config
|
|
150
242
|
self = cls(config)
|
|
151
|
-
|
|
152
|
-
|
|
243
|
+
|
|
244
|
+
init_event: threading.Event = threading.Event()
|
|
153
245
|
|
|
154
246
|
def init_callback(socket_path: Optional[str], err: Optional[str]):
|
|
155
247
|
if err is not None:
|
|
@@ -161,7 +253,7 @@ class BaseClient(CoreCommands):
|
|
|
161
253
|
else:
|
|
162
254
|
# Received socket path
|
|
163
255
|
self.socket_path = socket_path
|
|
164
|
-
|
|
256
|
+
init_event.set()
|
|
165
257
|
|
|
166
258
|
start_socket_listener_external(init_callback=init_callback)
|
|
167
259
|
|
|
@@ -169,36 +261,27 @@ class BaseClient(CoreCommands):
|
|
|
169
261
|
# level or higher
|
|
170
262
|
ClientLogger.log(LogLevel.INFO, "connection info", "new connection established")
|
|
171
263
|
# Wait for the socket listener to complete its initialization
|
|
172
|
-
await
|
|
264
|
+
await to_thread.run_sync(init_event.wait)
|
|
173
265
|
# Create UDS connection
|
|
174
266
|
await self._create_uds_connection()
|
|
267
|
+
|
|
175
268
|
# Start the reader loop as a background task
|
|
176
|
-
self._reader_task =
|
|
269
|
+
self._reader_task = self._create_task(self._reader_loop)
|
|
270
|
+
|
|
177
271
|
# Set the client configurations
|
|
178
272
|
await self._set_connection_configurations()
|
|
273
|
+
|
|
179
274
|
return self
|
|
180
275
|
|
|
181
276
|
async def _create_uds_connection(self) -> None:
|
|
182
277
|
try:
|
|
183
278
|
# Open an UDS connection
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
path=self.socket_path
|
|
279
|
+
with anyio.fail_after(DEFAULT_TIMEOUT_IN_MILLISECONDS):
|
|
280
|
+
self._stream = await anyio.connect_unix(
|
|
281
|
+
path=cast(str, self.socket_path)
|
|
187
282
|
)
|
|
188
|
-
self._reader = reader
|
|
189
|
-
self._writer = writer
|
|
190
283
|
except Exception as e:
|
|
191
|
-
|
|
192
|
-
raise
|
|
193
|
-
|
|
194
|
-
def __del__(self) -> None:
|
|
195
|
-
try:
|
|
196
|
-
if self._reader_task:
|
|
197
|
-
self._reader_task.cancel()
|
|
198
|
-
except RuntimeError as e:
|
|
199
|
-
if "no running event loop" in str(e):
|
|
200
|
-
# event loop already closed
|
|
201
|
-
pass
|
|
284
|
+
raise ClosingError("Failed to create UDS connection") from e
|
|
202
285
|
|
|
203
286
|
async def close(self, err_message: Optional[str] = None) -> None:
|
|
204
287
|
"""
|
|
@@ -210,25 +293,24 @@ class BaseClient(CoreCommands):
|
|
|
210
293
|
closing all open futures.
|
|
211
294
|
Defaults to None.
|
|
212
295
|
"""
|
|
213
|
-
self._is_closed
|
|
214
|
-
|
|
215
|
-
if
|
|
216
|
-
|
|
217
|
-
response_future.
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
pubsub_future.
|
|
223
|
-
|
|
224
|
-
|
|
296
|
+
if not self._is_closed:
|
|
297
|
+
self._is_closed = True
|
|
298
|
+
err_message = "" if err_message is None else err_message
|
|
299
|
+
for response_future in self._available_futures.values():
|
|
300
|
+
if not response_future.done():
|
|
301
|
+
response_future.set_exception(ClosingError(err_message))
|
|
302
|
+
try:
|
|
303
|
+
self._pubsub_lock.acquire()
|
|
304
|
+
for pubsub_future in self._pubsub_futures:
|
|
305
|
+
if not pubsub_future.done():
|
|
306
|
+
pubsub_future.set_exception(ClosingError(err_message))
|
|
307
|
+
finally:
|
|
308
|
+
self._pubsub_lock.release()
|
|
225
309
|
|
|
226
|
-
|
|
227
|
-
await self._writer.wait_closed()
|
|
228
|
-
self.__del__()
|
|
310
|
+
await self._stream.aclose()
|
|
229
311
|
|
|
230
|
-
def _get_future(self, callback_idx: int) ->
|
|
231
|
-
response_future:
|
|
312
|
+
def _get_future(self, callback_idx: int) -> "TFuture":
|
|
313
|
+
response_future: "TFuture" = _get_new_future_instance()
|
|
232
314
|
self._available_futures.update({callback_idx: response_future})
|
|
233
315
|
return response_future
|
|
234
316
|
|
|
@@ -237,14 +319,15 @@ class BaseClient(CoreCommands):
|
|
|
237
319
|
|
|
238
320
|
async def _set_connection_configurations(self) -> None:
|
|
239
321
|
conn_request = self._get_protobuf_conn_request()
|
|
240
|
-
response_future:
|
|
241
|
-
|
|
322
|
+
response_future: "TFuture" = self._get_future(0)
|
|
323
|
+
self._create_write_task(conn_request)
|
|
242
324
|
await response_future
|
|
243
|
-
|
|
244
|
-
|
|
325
|
+
res = response_future.result()
|
|
326
|
+
if res is not OK:
|
|
327
|
+
raise ClosingError(res)
|
|
245
328
|
|
|
246
329
|
def _create_write_task(self, request: TRequest):
|
|
247
|
-
|
|
330
|
+
self._create_task(self._write_or_buffer_request, request)
|
|
248
331
|
|
|
249
332
|
async def _write_or_buffer_request(self, request: TRequest):
|
|
250
333
|
self._buffered_requests.append(request)
|
|
@@ -252,7 +335,21 @@ class BaseClient(CoreCommands):
|
|
|
252
335
|
try:
|
|
253
336
|
while len(self._buffered_requests) > 0:
|
|
254
337
|
await self._write_buffered_requests_to_socket()
|
|
255
|
-
|
|
338
|
+
except Exception as e:
|
|
339
|
+
# trio system tasks cannot raise exceptions, so gracefully propagate
|
|
340
|
+
# any error to the pending future instead
|
|
341
|
+
callback_idx = (
|
|
342
|
+
request.callback_idx if isinstance(request, CommandRequest) else 0
|
|
343
|
+
)
|
|
344
|
+
res_future = self._available_futures.pop(callback_idx, None)
|
|
345
|
+
if res_future:
|
|
346
|
+
res_future.set_exception(e)
|
|
347
|
+
else:
|
|
348
|
+
ClientLogger.log(
|
|
349
|
+
LogLevel.WARN,
|
|
350
|
+
"unhandled response error",
|
|
351
|
+
f"Unhandled response error for unknown request: {callback_idx}",
|
|
352
|
+
)
|
|
256
353
|
finally:
|
|
257
354
|
self._writer_lock.release()
|
|
258
355
|
|
|
@@ -262,8 +359,7 @@ class BaseClient(CoreCommands):
|
|
|
262
359
|
b_arr = bytearray()
|
|
263
360
|
for request in requests:
|
|
264
361
|
ProtobufCodec.encode_delimited(b_arr, request)
|
|
265
|
-
self.
|
|
266
|
-
await self._writer.drain()
|
|
362
|
+
await self._stream.send(b_arr)
|
|
267
363
|
|
|
268
364
|
def _encode_arg(self, arg: TEncodable) -> bytes:
|
|
269
365
|
"""
|
|
@@ -301,7 +397,7 @@ class BaseClient(CoreCommands):
|
|
|
301
397
|
for arg in args_list:
|
|
302
398
|
encoded_arg = self._encode_arg(arg) if isinstance(arg, str) else arg
|
|
303
399
|
encoded_args_list.append(encoded_arg)
|
|
304
|
-
args_size +=
|
|
400
|
+
args_size += sys.getsizeof(encoded_arg)
|
|
305
401
|
return (encoded_args_list, args_size)
|
|
306
402
|
|
|
307
403
|
async def _execute_command(
|
|
@@ -417,14 +513,15 @@ class BaseClient(CoreCommands):
|
|
|
417
513
|
)
|
|
418
514
|
|
|
419
515
|
# locking might not be required
|
|
420
|
-
response_future:
|
|
516
|
+
response_future: "TFuture" = _get_new_future_instance()
|
|
421
517
|
try:
|
|
422
518
|
self._pubsub_lock.acquire()
|
|
423
519
|
self._pubsub_futures.append(response_future)
|
|
424
520
|
self._complete_pubsub_futures_safe()
|
|
425
521
|
finally:
|
|
426
522
|
self._pubsub_lock.release()
|
|
427
|
-
|
|
523
|
+
await response_future
|
|
524
|
+
return response_future.result()
|
|
428
525
|
|
|
429
526
|
def try_get_pubsub_message(self) -> Optional[CoreCommands.PubSubMsg]:
|
|
430
527
|
if self._is_closed:
|
|
@@ -457,8 +554,7 @@ class BaseClient(CoreCommands):
|
|
|
457
554
|
def _cancel_pubsub_futures_with_exception_safe(self, exception: ConnectionError):
|
|
458
555
|
while len(self._pubsub_futures):
|
|
459
556
|
next_future = self._pubsub_futures.pop(0)
|
|
460
|
-
|
|
461
|
-
next_future.set_exception(exception)
|
|
557
|
+
next_future.set_exception(exception)
|
|
462
558
|
|
|
463
559
|
def _notification_to_pubsub_message_safe(
|
|
464
560
|
self, response: Response
|
|
@@ -538,10 +634,16 @@ class BaseClient(CoreCommands):
|
|
|
538
634
|
if response.HasField("closing_error")
|
|
539
635
|
else f"Client Error - closing due to unknown error. callback index: {response.callback_idx}"
|
|
540
636
|
)
|
|
637
|
+
exc = ClosingError(err_msg)
|
|
541
638
|
if res_future is not None:
|
|
542
|
-
res_future.set_exception(
|
|
543
|
-
|
|
544
|
-
|
|
639
|
+
res_future.set_exception(exc)
|
|
640
|
+
else:
|
|
641
|
+
ClientLogger.log(
|
|
642
|
+
LogLevel.WARN,
|
|
643
|
+
"unhandled response error",
|
|
644
|
+
f"Unhandled response error for unknown request: {response.callback_idx}",
|
|
645
|
+
)
|
|
646
|
+
raise exc
|
|
545
647
|
else:
|
|
546
648
|
self._available_callback_indexes.append(response.callback_idx)
|
|
547
649
|
if response.HasField("request_error"):
|
|
@@ -561,9 +663,7 @@ class BaseClient(CoreCommands):
|
|
|
561
663
|
if response.HasField("closing_error")
|
|
562
664
|
else "Client Error - push notification without resp_pointer"
|
|
563
665
|
)
|
|
564
|
-
await self.close(err_msg)
|
|
565
666
|
raise ClosingError(err_msg)
|
|
566
|
-
|
|
567
667
|
try:
|
|
568
668
|
self._pubsub_lock.acquire()
|
|
569
669
|
callback, context = self.config._get_pubsub_callback_and_context()
|
|
@@ -579,30 +679,36 @@ class BaseClient(CoreCommands):
|
|
|
579
679
|
|
|
580
680
|
async def _reader_loop(self) -> None:
|
|
581
681
|
# Socket reader loop
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
if len(read_bytes) == 0:
|
|
586
|
-
err_msg = "The communication layer was unexpectedly closed."
|
|
587
|
-
await self.close(err_msg)
|
|
588
|
-
raise ClosingError(err_msg)
|
|
589
|
-
read_bytes = remaining_read_bytes + bytearray(read_bytes)
|
|
590
|
-
read_bytes_view = memoryview(read_bytes)
|
|
591
|
-
offset = 0
|
|
592
|
-
while offset <= len(read_bytes):
|
|
682
|
+
try:
|
|
683
|
+
remaining_read_bytes = bytearray()
|
|
684
|
+
while True:
|
|
593
685
|
try:
|
|
594
|
-
|
|
595
|
-
|
|
686
|
+
read_bytes = await self._stream.receive(DEFAULT_READ_BYTES_SIZE)
|
|
687
|
+
except (anyio.ClosedResourceError, anyio.EndOfStream):
|
|
688
|
+
raise ClosingError(
|
|
689
|
+
"The communication layer was unexpectedly closed."
|
|
596
690
|
)
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
691
|
+
read_bytes = remaining_read_bytes + bytearray(read_bytes)
|
|
692
|
+
read_bytes_view = memoryview(read_bytes)
|
|
693
|
+
offset = 0
|
|
694
|
+
while offset <= len(read_bytes):
|
|
695
|
+
try:
|
|
696
|
+
response, offset = ProtobufCodec.decode_delimited(
|
|
697
|
+
read_bytes, read_bytes_view, offset, Response
|
|
698
|
+
)
|
|
699
|
+
except PartialMessageException:
|
|
700
|
+
# Received only partial response, break the inner loop
|
|
701
|
+
remaining_read_bytes = read_bytes[offset:]
|
|
702
|
+
break
|
|
703
|
+
response = cast(Response, response)
|
|
704
|
+
if response.is_push:
|
|
705
|
+
await self._process_push(response=response)
|
|
706
|
+
else:
|
|
707
|
+
await self._process_response(response=response)
|
|
708
|
+
except Exception as e:
|
|
709
|
+
# close and stop reading at terminal exceptions from incoming responses or
|
|
710
|
+
# stream closures
|
|
711
|
+
await self.close(str(e))
|
|
606
712
|
|
|
607
713
|
async def get_statistics(self) -> dict:
|
|
608
714
|
return get_statistics()
|
glide/routes.py
CHANGED
|
@@ -10,9 +10,14 @@ from glide.protobuf.command_request_pb2 import SlotTypes as ProtoSlotTypes
|
|
|
10
10
|
|
|
11
11
|
class SlotType(Enum):
|
|
12
12
|
PRIMARY = 1
|
|
13
|
+
"""
|
|
14
|
+
Address a primary node.
|
|
15
|
+
"""
|
|
13
16
|
|
|
14
17
|
REPLICA = 2
|
|
15
18
|
"""
|
|
19
|
+
Address a replica node.
|
|
20
|
+
|
|
16
21
|
`REPLICA` overrides the `read_from_replica` configuration. If it's used the request
|
|
17
22
|
will be routed to a replica, even if the strategy is `ALWAYS_FROM_MASTER`.
|
|
18
23
|
"""
|
|
@@ -38,6 +43,10 @@ class AllNodes(Route):
|
|
|
38
43
|
|
|
39
44
|
|
|
40
45
|
class AllPrimaries(Route):
|
|
46
|
+
"""
|
|
47
|
+
Route request to all primary nodes.
|
|
48
|
+
"""
|
|
49
|
+
|
|
41
50
|
pass
|
|
42
51
|
|
|
43
52
|
|
|
@@ -53,6 +62,13 @@ class RandomNode(Route):
|
|
|
53
62
|
|
|
54
63
|
|
|
55
64
|
class SlotKeyRoute(Route):
|
|
65
|
+
"""Routes a request to a node by its slot key
|
|
66
|
+
|
|
67
|
+
Attributes:
|
|
68
|
+
slot_type (SlotType): Defines type of the node being addressed.
|
|
69
|
+
slot_key (str): The request will be sent to nodes managing this key.
|
|
70
|
+
"""
|
|
71
|
+
|
|
56
72
|
def __init__(self, slot_type: SlotType, slot_key: str) -> None:
|
|
57
73
|
super().__init__()
|
|
58
74
|
self.slot_type = slot_type
|
|
@@ -60,6 +76,15 @@ class SlotKeyRoute(Route):
|
|
|
60
76
|
|
|
61
77
|
|
|
62
78
|
class SlotIdRoute(Route):
|
|
79
|
+
"""Routes a request to a node by its slot ID
|
|
80
|
+
|
|
81
|
+
Attributes:
|
|
82
|
+
slot_type (SlotType): Defines type of the node being addressed.
|
|
83
|
+
slot_id (int): Slot number. There are 16384 slots in a Valkey cluster, and each shard
|
|
84
|
+
manages a slot range. Unless the slot is known, it's better to route using
|
|
85
|
+
`SlotType.PRIMARY`
|
|
86
|
+
"""
|
|
87
|
+
|
|
63
88
|
def __init__(self, slot_type: SlotType, slot_id: int) -> None:
|
|
64
89
|
super().__init__()
|
|
65
90
|
self.slot_type = slot_type
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: valkey-glide
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.0rc6
|
|
4
4
|
Classifier: Topic :: Database
|
|
5
5
|
Classifier: Topic :: Utilities
|
|
6
6
|
Classifier: License :: OSI Approved :: Apache Software License
|
|
@@ -9,7 +9,7 @@ Classifier: Topic :: Software Development
|
|
|
9
9
|
Classifier: Programming Language :: Rust
|
|
10
10
|
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
11
11
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
12
|
-
Requires-Dist:
|
|
12
|
+
Requires-Dist: anyio>=4.9.0
|
|
13
13
|
Requires-Dist: typing-extensions>=4.8.0; python_version < '3.11'
|
|
14
14
|
Requires-Dist: protobuf>=3.20
|
|
15
15
|
Summary: An open source Valkey client library that supports Valkey and Redis open source 6.2, 7.0, 7.2 and 8.0.
|
|
@@ -18,9 +18,19 @@ License: Apache-2.0
|
|
|
18
18
|
Requires-Python: >=3.9
|
|
19
19
|
Description-Content-Type: text/markdown; charset=UTF-8; variant=GFM
|
|
20
20
|
|
|
21
|
-
# Valkey GLIDE
|
|
21
|
+
# Welcome to Valkey GLIDE!
|
|
22
22
|
|
|
23
|
-
Valkey General Language Independent Driver for the Enterprise (GLIDE)
|
|
23
|
+
Valkey General Language Independent Driver for the Enterprise (GLIDE) is the official open-source Valkey client library, proudly part of the Valkey organization. Our mission is to make your experience with Valkey and Redis OSS seamless and enjoyable. Whether you're a seasoned developer or just starting out, Valkey GLIDE is here to support you every step of the way.
|
|
24
|
+
|
|
25
|
+
# Why Choose Valkey GLIDE?
|
|
26
|
+
|
|
27
|
+
- **Community and Open Source**: Join our vibrant community and contribute to the project. We are always here to respond, and the client is for the community.
|
|
28
|
+
- **Reliability**: Built with best practices learned from over a decade of operating Redis OSS-compatible services.
|
|
29
|
+
- **Performance**: Optimized for high performance and low latency.
|
|
30
|
+
- **High Availability**: Designed to ensure your applications are always up and running.
|
|
31
|
+
- **Cross-Language Support**: Implemented using a core driver framework written in Rust, with language-specific extensions to ensure consistency and reduce complexity.
|
|
32
|
+
- **Stability and Fault Tolerance**: We brought our years of experience to create a bulletproof client.
|
|
33
|
+
- **Backed and Supported by AWS and GCP**: Ensuring robust support and continuous improvement of the project.
|
|
24
34
|
|
|
25
35
|
## Documentation
|
|
26
36
|
|
|
@@ -47,6 +57,7 @@ Linux:
|
|
|
47
57
|
macOS:
|
|
48
58
|
|
|
49
59
|
- macOS 14.7 (Apple silicon/aarch_64)
|
|
60
|
+
- macOS 13.7 (x86_64/amd64)
|
|
50
61
|
|
|
51
62
|
## Python Supported Versions
|
|
52
63
|
|
|
@@ -58,6 +69,8 @@ macOS:
|
|
|
58
69
|
| 3.12 |
|
|
59
70
|
| 3.13 |
|
|
60
71
|
|
|
72
|
+
Valkey GLIDE transparently supports both the `asyncio` and `trio` concurrency frameworks.
|
|
73
|
+
|
|
61
74
|
## Installation and Setup
|
|
62
75
|
|
|
63
76
|
### Installing via Package Manager (pip)
|
|
@@ -125,3 +138,7 @@ For complete examples with error handling, please refer to the [cluster example]
|
|
|
125
138
|
|
|
126
139
|
Development instructions for local building & testing the package are in the [DEVELOPER.md](https://github.com/valkey-io/valkey-glide/blob/main/python/DEVELOPER.md#build-from-source) file.
|
|
127
140
|
|
|
141
|
+
## Community and Feedback
|
|
142
|
+
|
|
143
|
+
We encourage you to join our community to support, share feedback, and ask questions. You can approach us for anything on our Valkey Slack: [Join Valkey Slack](https://join.slack.com/t/valkey-oss-developer/shared_invite/zt-2nxs51chx-EB9hu9Qdch3GMfRcztTSkQ).
|
|
144
|
+
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
valkey_glide-2.0.
|
|
2
|
-
valkey_glide-2.0.
|
|
1
|
+
valkey_glide-2.0.0rc6.dist-info/METADATA,sha256=yOI45wSVq6bfF0HKNWungAYTiHdVrsLyn_lf57cznRg,5650
|
|
2
|
+
valkey_glide-2.0.0rc6.dist-info/WHEEL,sha256=_QtxoP9D772USLcb64TnAfT22LQ_jIQ90FIrxZisaUM,133
|
|
3
3
|
glide/config.py,sha256=1IkmvCPLU9nm7EpwcvYT3URoLWApWGr6eSRmuyPXDyA,28891
|
|
4
4
|
glide/glide.pyi,sha256=K2CeC-F0E8vlr-rbko-E0PofzFoWl4da-xUQSuvuFDo,1105
|
|
5
5
|
glide/__init__.py,sha256=nCbDQf344sIuXbaCsivrjBjkQ3kaP_ArT3IQnzTUFx8,7372
|
|
6
|
-
glide/glide_client.py,sha256=
|
|
6
|
+
glide/glide_client.py,sha256=E6bS-Yu9XNKERD9QjWm4ukbdjMPD17KtWPXLddhBvXQ,31880
|
|
7
7
|
glide/exceptions.py,sha256=ZI_LwIduoR-1jHm9-6jWZkx90AqCJLRtjbv4iESIEEA,1194
|
|
8
8
|
glide/protobuf_codec.py,sha256=xwt4-D4WbvNIY_vjOd-00c73HOyNjWq7nN-Z718PBVA,3667
|
|
9
9
|
glide/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -13,11 +13,11 @@ glide/protobuf/command_request_pb2.py,sha256=Kl07aQBGu8i3oFqbT-uZByWVaTCjYuDeYb0
|
|
|
13
13
|
glide/protobuf/command_request_pb2.pyi,sha256=DYnPAmwzyygCdCpW1R1CDGZB_O6zQRJp51K8Wr4CpFc,52470
|
|
14
14
|
glide/protobuf/response_pb2.pyi,sha256=f7E-n7cba9UsVVVFn5YuetEvS1_aME70aeNt5n4Kwm8,4152
|
|
15
15
|
glide/protobuf/response_pb2.py,sha256=r3_OFhf8HZvEmBSigSyBzG7S7kWl7CCgVMog4HgMFXM,2025
|
|
16
|
-
glide/routes.py,sha256=
|
|
16
|
+
glide/routes.py,sha256=ZcLV_HrMzAYxHJW7uk905gdhOZbchBDSHlG1LVF7BJ4,4439
|
|
17
17
|
glide/constants.py,sha256=Kb-wTQrcshjCivNXcrrOzz7xp7pNL_-Gt6Updiq9k4o,4354
|
|
18
18
|
glide/logger.py,sha256=IhlrmIDF4IufCOszQu2WnMZeyBfH21kVr8KwDlBqDP0,3800
|
|
19
19
|
glide/async_commands/bitmap.py,sha256=ZHGLcKBP7RADtANqIR7PWdIW_gfDBFgpkIsQ-T4QFBQ,10125
|
|
20
|
-
glide/async_commands/cluster_commands.py,sha256=
|
|
20
|
+
glide/async_commands/cluster_commands.py,sha256=trG0vZCMZxrkziYBFlFvLZ3nMUvfS6r-BRkRwb9Gif0,61994
|
|
21
21
|
glide/async_commands/__init__.py,sha256=_tbTAFATlzp4L2qe-H77PpAQK-16VsV-y7uKNUKLC_o,136
|
|
22
22
|
glide/async_commands/server_modules/glide_json.py,sha256=cf93MG6GioA7hFLPn1vNMjipoUt6G-qJ2oK9E91KRkw,63120
|
|
23
23
|
glide/async_commands/server_modules/ft_options/ft_search_options.py,sha256=q72JVuLMFIVWXDOe0IQWTYFZYNiPSE6Yo3fKIn27hTA,4855
|
|
@@ -27,11 +27,11 @@ glide/async_commands/server_modules/ft_options/ft_profile_options.py,sha256=19t7
|
|
|
27
27
|
glide/async_commands/server_modules/ft_options/ft_aggregate_options.py,sha256=hnutaOAZB5iFNJ_GKK2K48gm-iiuR-rhaCFUOD6VtBM,9919
|
|
28
28
|
glide/async_commands/server_modules/ft.py,sha256=xOV22Znj9z9clKK5XZUL8UhthSbiA1F2H11EOKtMJCg,16840
|
|
29
29
|
glide/async_commands/server_modules/json_batch.py,sha256=XBySnoRJnm1ABPYBnajHmPK6C-Wr9uk3gjNg2s7wVm8,36631
|
|
30
|
-
glide/async_commands/batch.py,sha256=
|
|
30
|
+
glide/async_commands/batch.py,sha256=MMNXtdY7cOCXuFCkHoliZIejZZJb0ApJWxJuXXinGsU,230704
|
|
31
31
|
glide/async_commands/sorted_set.py,sha256=nALPJQNNjW7dAqXMDJIur_xDwnJzQCdqxtx5zXYCRNM,11458
|
|
32
32
|
glide/async_commands/stream.py,sha256=y3tmuOc-Ndnjvc__xybBcf2wqoNUQ1H1hPXYerpwNA8,15582
|
|
33
|
-
glide/async_commands/core.py,sha256=
|
|
34
|
-
glide/async_commands/standalone_commands.py,sha256=
|
|
33
|
+
glide/async_commands/core.py,sha256=ZYjUwpf7DJBlBC7KPHSiRjbA6lbWcBbY8xEGxkJXRno,316713
|
|
34
|
+
glide/async_commands/standalone_commands.py,sha256=vfqXTIU5YLMsHUD9MD3Qi1vccD9QMSQuH38mpo_5rjU,39510
|
|
35
35
|
glide/async_commands/command_args.py,sha256=55vpSxeQr8wFU7olkFTEecl66wPk1g6vWxVYj16UvXs,2529
|
|
36
|
-
glide/glide.cpython-312-aarch64-linux-gnu.so,sha256=
|
|
37
|
-
valkey_glide-2.0.
|
|
36
|
+
glide/glide.cpython-312-aarch64-linux-gnu.so,sha256=qrlkW8vnvocQb5G2GWWvnr7w5755LPAdgNB9kO1Hdmw,6767144
|
|
37
|
+
valkey_glide-2.0.0rc6.dist-info/RECORD,,
|
|
File without changes
|