valkey-glide 2.0.0rc5__cp311-cp311-macosx_11_0_arm64.whl → 2.0.0rc7__cp311-cp311-macosx_11_0_arm64.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 +35 -24
- glide/async_commands/cluster_commands.py +7 -1
- glide/async_commands/core.py +20 -20
- glide/async_commands/standalone_commands.py +8 -1
- glide/glide.cpython-311-darwin.so +0 -0
- glide/glide_client.py +190 -84
- glide/routes.py +25 -0
- {valkey_glide-2.0.0rc5.dist-info → valkey_glide-2.0.0rc7.dist-info}/METADATA +21 -4
- {valkey_glide-2.0.0rc5.dist-info → valkey_glide-2.0.0rc7.dist-info}/RECORD +10 -10
- {valkey_glide-2.0.0rc5.dist-info → valkey_glide-2.0.0rc7.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,
|
|
@@ -57,6 +57,11 @@ from glide.async_commands.stream import (
|
|
|
57
57
|
from glide.constants import TEncodable
|
|
58
58
|
from glide.protobuf.command_request_pb2 import RequestType
|
|
59
59
|
|
|
60
|
+
if sys.version_info >= (3, 13):
|
|
61
|
+
from warnings import deprecated
|
|
62
|
+
else:
|
|
63
|
+
from typing_extensions import deprecated
|
|
64
|
+
|
|
60
65
|
TBatch = TypeVar("TBatch", bound="BaseBatch")
|
|
61
66
|
|
|
62
67
|
|
|
@@ -109,7 +114,7 @@ class BaseBatch:
|
|
|
109
114
|
|
|
110
115
|
def get(self: TBatch, key: TEncodable) -> TBatch:
|
|
111
116
|
"""
|
|
112
|
-
Get the value associated with the given key, or null if no such
|
|
117
|
+
Get the value associated with the given key, or null if no such key exists.
|
|
113
118
|
|
|
114
119
|
See [valkey.io](https://valkey.io/commands/get/) for details.
|
|
115
120
|
|
|
@@ -273,6 +278,10 @@ class BaseBatch:
|
|
|
273
278
|
[custom command](https://github.com/valkey-io/valkey-glide/wiki/General-Concepts#custom-command)
|
|
274
279
|
for details on the restrictions and limitations of the custom command API.
|
|
275
280
|
|
|
281
|
+
This function should only be used for single-response commands. Commands that don't return complete response and awaits
|
|
282
|
+
(such as SUBSCRIBE), or that return potentially more than a single response (such as XREAD), or that change the
|
|
283
|
+
client's behavior (such as entering pub/sub mode on RESP2 connections) shouldn't be called using this function.
|
|
284
|
+
|
|
276
285
|
Args:
|
|
277
286
|
command_args (List[TEncodable]): List of command arguments.
|
|
278
287
|
Every part of the command, including the command name and subcommands, should be added as a
|
|
@@ -312,6 +321,8 @@ class BaseBatch:
|
|
|
312
321
|
"""
|
|
313
322
|
Get information and statistics about the server.
|
|
314
323
|
|
|
324
|
+
Starting from server version 7, command supports multiple section arguments.
|
|
325
|
+
|
|
315
326
|
See [valkey.io](https://valkey.io/commands/info/) for details.
|
|
316
327
|
|
|
317
328
|
Args:
|
|
@@ -1057,7 +1068,7 @@ class BaseBatch:
|
|
|
1057
1068
|
Command response:
|
|
1058
1069
|
Optional[Mapping[bytes, List[bytes]]]: A map of `key` name mapped to an array of popped elements.
|
|
1059
1070
|
|
|
1060
|
-
None if no elements could be popped.
|
|
1071
|
+
`None` if no elements could be popped.
|
|
1061
1072
|
|
|
1062
1073
|
Since: Valkey version 7.0.0.
|
|
1063
1074
|
"""
|
|
@@ -2412,26 +2423,26 @@ class BaseBatch:
|
|
|
2412
2423
|
|
|
2413
2424
|
Args:
|
|
2414
2425
|
key (TEncodable): The key of the stream.
|
|
2415
|
-
start (StreamRangeBound): The starting stream ID bound for the range.
|
|
2426
|
+
start (StreamRangeBound): The starting stream entry ID bound for the range.
|
|
2416
2427
|
|
|
2417
|
-
- Use `IdBound` to specify a stream ID.
|
|
2418
|
-
-
|
|
2428
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
2429
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
2419
2430
|
- Use `MinId` to start with the minimum available ID.
|
|
2420
2431
|
|
|
2421
|
-
end (StreamRangeBound): The ending stream ID bound for the range.
|
|
2432
|
+
end (StreamRangeBound): The ending stream entry ID bound for the range.
|
|
2422
2433
|
|
|
2423
|
-
- Use `IdBound` to specify a stream ID.
|
|
2424
|
-
-
|
|
2434
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
2435
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
2425
2436
|
- Use `MaxId` to end with the maximum available ID.
|
|
2426
2437
|
|
|
2427
2438
|
count (Optional[int]): An optional argument specifying the maximum count of stream entries to return.
|
|
2428
2439
|
If `count` is not provided, all stream entries in the range will be returned.
|
|
2429
2440
|
|
|
2430
2441
|
Command response:
|
|
2431
|
-
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream IDs to stream entry data, where entry data is a
|
|
2442
|
+
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream entry IDs to stream entry data, where entry data is a
|
|
2432
2443
|
list of pairings with format `[[field, entry], [field, entry], ...]`.
|
|
2433
2444
|
|
|
2434
|
-
Returns None if the range arguments are not applicable.
|
|
2445
|
+
Returns None if the range arguments are not applicable. Or if count is non-positive.
|
|
2435
2446
|
"""
|
|
2436
2447
|
args = [key, start.to_arg(), end.to_arg()]
|
|
2437
2448
|
if count is not None:
|
|
@@ -2454,26 +2465,26 @@ class BaseBatch:
|
|
|
2454
2465
|
|
|
2455
2466
|
Args:
|
|
2456
2467
|
key (TEncodable): The key of the stream.
|
|
2457
|
-
end (StreamRangeBound): The ending stream ID bound for the range.
|
|
2468
|
+
end (StreamRangeBound): The ending stream entry ID bound for the range.
|
|
2458
2469
|
|
|
2459
|
-
- Use `IdBound` to specify a stream ID.
|
|
2460
|
-
-
|
|
2470
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
2471
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
2461
2472
|
- Use `MaxId` to end with the maximum available ID.
|
|
2462
2473
|
|
|
2463
|
-
start (StreamRangeBound): The starting stream ID bound for the range.
|
|
2474
|
+
start (StreamRangeBound): The starting stream entry ID bound for the range.
|
|
2464
2475
|
|
|
2465
|
-
- Use `IdBound` to specify a stream ID.
|
|
2466
|
-
-
|
|
2476
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
2477
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
2467
2478
|
- Use `MinId` to start with the minimum available ID.
|
|
2468
2479
|
|
|
2469
2480
|
count (Optional[int]): An optional argument specifying the maximum count of stream entries to return.
|
|
2470
2481
|
If `count` is not provided, all stream entries in the range will be returned.
|
|
2471
2482
|
|
|
2472
2483
|
Command response:
|
|
2473
|
-
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream IDs to stream entry data, where entry data is a
|
|
2484
|
+
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream entry IDs to stream entry data, where entry data is a
|
|
2474
2485
|
list of pairings with format `[[field, entry], [field, entry], ...]`.
|
|
2475
2486
|
|
|
2476
|
-
Returns None if the range arguments are not applicable.
|
|
2487
|
+
Returns None if the range arguments are not applicable. Or if count is non-positive.
|
|
2477
2488
|
"""
|
|
2478
2489
|
args = [key, end.to_arg(), start.to_arg()]
|
|
2479
2490
|
if count is not None:
|
|
@@ -2787,7 +2798,7 @@ class BaseBatch:
|
|
|
2787
2798
|
min_idle_time_ms (int): Filters the claimed entries to those that have been idle for more than the specified
|
|
2788
2799
|
value.
|
|
2789
2800
|
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.
|
|
2801
|
+
count (Optional[int]): Limits the number of claimed entries to the specified value. Default value is 100.
|
|
2791
2802
|
|
|
2792
2803
|
Command response:
|
|
2793
2804
|
List[Union[str, Mapping[bytes, List[List[bytes]]], List[bytes]]]: A list containing the following elements:
|
|
@@ -2832,7 +2843,7 @@ class BaseBatch:
|
|
|
2832
2843
|
min_idle_time_ms (int): Filters the claimed entries to those that have been idle for more than the specified
|
|
2833
2844
|
value.
|
|
2834
2845
|
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.
|
|
2846
|
+
count (Optional[int]): Limits the number of claimed entries to the specified value. Default value is 100.
|
|
2836
2847
|
|
|
2837
2848
|
Command response:
|
|
2838
2849
|
List[Union[bytes, List[bytes]]]: A list containing the following elements:
|
|
@@ -3263,7 +3274,7 @@ class BaseBatch:
|
|
|
3263
3274
|
Commands response:
|
|
3264
3275
|
Optional[float]: The score of the member.
|
|
3265
3276
|
|
|
3266
|
-
If there was a conflict with choosing the XX/NX/LT/GT options, the operation aborts and None is returned.
|
|
3277
|
+
If there was a conflict with choosing the XX/NX/LT/GT options, the operation aborts and `None` is returned.
|
|
3267
3278
|
"""
|
|
3268
3279
|
args = [key]
|
|
3269
3280
|
if existing_options:
|
|
@@ -5573,13 +5584,13 @@ class ClusterBatch(BaseBatch):
|
|
|
5573
5584
|
# TODO: add all CLUSTER commands
|
|
5574
5585
|
|
|
5575
5586
|
|
|
5576
|
-
@deprecated(
|
|
5587
|
+
@deprecated("Use Batch(is_atomic=True) instead.")
|
|
5577
5588
|
class Transaction(Batch):
|
|
5578
5589
|
def __init__(self):
|
|
5579
5590
|
super().__init__(is_atomic=True)
|
|
5580
5591
|
|
|
5581
5592
|
|
|
5582
|
-
@deprecated(
|
|
5593
|
+
@deprecated("Use ClusterBatch(is_atomic=True) instead.")
|
|
5583
5594
|
class ClusterTransaction(ClusterBatch):
|
|
5584
5595
|
def __init__(self):
|
|
5585
5596
|
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
|
@@ -593,7 +593,7 @@ class CoreCommands(Protocol):
|
|
|
593
593
|
|
|
594
594
|
async def get(self, key: TEncodable) -> Optional[bytes]:
|
|
595
595
|
"""
|
|
596
|
-
Get the value associated with the given key, or null if no such
|
|
596
|
+
Get the value associated with the given key, or null if no such key exists.
|
|
597
597
|
|
|
598
598
|
See [valkey.io](https://valkey.io/commands/get/) for details.
|
|
599
599
|
|
|
@@ -3114,26 +3114,26 @@ class CoreCommands(Protocol):
|
|
|
3114
3114
|
|
|
3115
3115
|
Args:
|
|
3116
3116
|
key (TEncodable): The key of the stream.
|
|
3117
|
-
start (StreamRangeBound): The starting stream ID bound for the range.
|
|
3117
|
+
start (StreamRangeBound): The starting stream entry ID bound for the range.
|
|
3118
3118
|
|
|
3119
|
-
- Use `IdBound` to specify a stream ID.
|
|
3120
|
-
-
|
|
3119
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
3120
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
3121
3121
|
- Use `MinId` to start with the minimum available ID.
|
|
3122
3122
|
|
|
3123
|
-
end (StreamRangeBound): The ending stream ID bound for the range.
|
|
3123
|
+
end (StreamRangeBound): The ending stream entry ID bound for the range.
|
|
3124
3124
|
|
|
3125
|
-
- Use `IdBound` to specify a stream ID.
|
|
3126
|
-
-
|
|
3125
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
3126
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
3127
3127
|
- Use `MaxId` to end with the maximum available ID.
|
|
3128
3128
|
|
|
3129
3129
|
count (Optional[int]): An optional argument specifying the maximum count of stream entries to return.
|
|
3130
3130
|
If `count` is not provided, all stream entries in the range will be returned.
|
|
3131
3131
|
|
|
3132
3132
|
Returns:
|
|
3133
|
-
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream IDs to stream entry data, where entry data is a
|
|
3133
|
+
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream entry IDs to stream entry data, where entry data is a
|
|
3134
3134
|
list of pairings with format `[[field, entry], [field, entry], ...]`.
|
|
3135
3135
|
|
|
3136
|
-
Returns None if the range arguments are not applicable.
|
|
3136
|
+
Returns None if the range arguments are not applicable. Or if count is non-positive.
|
|
3137
3137
|
|
|
3138
3138
|
Examples:
|
|
3139
3139
|
>>> await client.xadd("mystream", [("field1", "value1")], StreamAddOptions(id="0-1"))
|
|
@@ -3168,26 +3168,26 @@ class CoreCommands(Protocol):
|
|
|
3168
3168
|
|
|
3169
3169
|
Args:
|
|
3170
3170
|
key (TEncodable): The key of the stream.
|
|
3171
|
-
end (StreamRangeBound): The ending stream ID bound for the range.
|
|
3171
|
+
end (StreamRangeBound): The ending stream entry ID bound for the range.
|
|
3172
3172
|
|
|
3173
|
-
- Use `IdBound` to specify a stream ID.
|
|
3174
|
-
-
|
|
3173
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
3174
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
3175
3175
|
- Use `MaxId` to end with the maximum available ID.
|
|
3176
3176
|
|
|
3177
|
-
start (StreamRangeBound): The starting stream ID bound for the range.
|
|
3177
|
+
start (StreamRangeBound): The starting stream entry ID bound for the range.
|
|
3178
3178
|
|
|
3179
|
-
- Use `IdBound` to specify a stream ID.
|
|
3180
|
-
-
|
|
3179
|
+
- Use `IdBound` to specify a stream entry ID.
|
|
3180
|
+
- Since Valkey 6.2.0, use `ExclusiveIdBound` to specify an exclusive bounded stream entry ID.
|
|
3181
3181
|
- Use `MinId` to start with the minimum available ID.
|
|
3182
3182
|
|
|
3183
3183
|
count (Optional[int]): An optional argument specifying the maximum count of stream entries to return.
|
|
3184
3184
|
If `count` is not provided, all stream entries in the range will be returned.
|
|
3185
3185
|
|
|
3186
3186
|
Returns:
|
|
3187
|
-
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream IDs to stream entry data, where entry data is a
|
|
3187
|
+
Optional[Mapping[bytes, List[List[bytes]]]]: A mapping of stream entry IDs to stream entry data, where entry data is a
|
|
3188
3188
|
list of pairings with format `[[field, entry], [field, entry], ...]`.
|
|
3189
3189
|
|
|
3190
|
-
Returns None if the range arguments are not applicable.
|
|
3190
|
+
Returns None if the range arguments are not applicable. Or if count is non-positive.
|
|
3191
3191
|
|
|
3192
3192
|
Examples:
|
|
3193
3193
|
>>> await client.xadd("mystream", [("field1", "value1")], StreamAddOptions(id="0-1"))
|
|
@@ -3273,7 +3273,7 @@ class CoreCommands(Protocol):
|
|
|
3273
3273
|
key (TEncodable): The key of the stream.
|
|
3274
3274
|
group_name (TEncodable): The newly created consumer group name.
|
|
3275
3275
|
group_id (TEncodable): The stream entry ID that specifies the last delivered entry in the stream from the new
|
|
3276
|
-
group
|
|
3276
|
+
group's perspective. The special ID "$" can be used to specify the last entry in the stream.
|
|
3277
3277
|
options (Optional[StreamGroupOptions]): Options for creating the stream group.
|
|
3278
3278
|
|
|
3279
3279
|
Returns:
|
|
@@ -3733,7 +3733,7 @@ class CoreCommands(Protocol):
|
|
|
3733
3733
|
min_idle_time_ms (int): Filters the claimed entries to those that have been idle for more than the specified
|
|
3734
3734
|
value.
|
|
3735
3735
|
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.
|
|
3736
|
+
count (Optional[int]): Limits the number of claimed entries to the specified value. Default value is 100.
|
|
3737
3737
|
|
|
3738
3738
|
Returns:
|
|
3739
3739
|
List[Union[bytes, Mapping[bytes, List[List[bytes]]], List[bytes]]]: A list containing the following elements:
|
|
@@ -3820,7 +3820,7 @@ class CoreCommands(Protocol):
|
|
|
3820
3820
|
min_idle_time_ms (int): Filters the claimed entries to those that have been idle for more than the specified
|
|
3821
3821
|
value.
|
|
3822
3822
|
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.
|
|
3823
|
+
count (Optional[int]): Limits the number of claimed entries to the specified value. Default value is 100.
|
|
3824
3824
|
|
|
3825
3825
|
Returns:
|
|
3826
3826
|
List[Union[bytes, List[bytes]]]: A list containing the following elements:
|
|
@@ -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
|
"""
|
|
@@ -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.0rc7
|
|
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,12 +1,12 @@
|
|
|
1
|
-
valkey_glide-2.0.
|
|
2
|
-
valkey_glide-2.0.
|
|
1
|
+
valkey_glide-2.0.0rc7.dist-info/METADATA,sha256=JZCHx9sqjhS0Tj05RJ22jjPa_QvUQmDfNMQ0IknjfHE,5650
|
|
2
|
+
valkey_glide-2.0.0rc7.dist-info/WHEEL,sha256=8hoTVLxyLdG351Jq1HozDQCHHiKu32mfNA2_wpcO9P4,106
|
|
3
3
|
glide/config.py,sha256=1IkmvCPLU9nm7EpwcvYT3URoLWApWGr6eSRmuyPXDyA,28891
|
|
4
4
|
glide/protobuf_codec.py,sha256=xwt4-D4WbvNIY_vjOd-00c73HOyNjWq7nN-Z718PBVA,3667
|
|
5
5
|
glide/constants.py,sha256=Kb-wTQrcshjCivNXcrrOzz7xp7pNL_-Gt6Updiq9k4o,4354
|
|
6
6
|
glide/async_commands/sorted_set.py,sha256=nALPJQNNjW7dAqXMDJIur_xDwnJzQCdqxtx5zXYCRNM,11458
|
|
7
|
-
glide/async_commands/batch.py,sha256=
|
|
7
|
+
glide/async_commands/batch.py,sha256=DOCXFbIZWNuBzIi_6P1Qt3HvRZVblBwoUxr_4imE8A4,230468
|
|
8
8
|
glide/async_commands/__init__.py,sha256=_tbTAFATlzp4L2qe-H77PpAQK-16VsV-y7uKNUKLC_o,136
|
|
9
|
-
glide/async_commands/core.py,sha256=
|
|
9
|
+
glide/async_commands/core.py,sha256=NS8jfMonU46KGPUZV5csKAueajwZlhs5FJI-aCSlLBY,316484
|
|
10
10
|
glide/async_commands/server_modules/glide_json.py,sha256=cf93MG6GioA7hFLPn1vNMjipoUt6G-qJ2oK9E91KRkw,63120
|
|
11
11
|
glide/async_commands/server_modules/json_batch.py,sha256=XBySnoRJnm1ABPYBnajHmPK6C-Wr9uk3gjNg2s7wVm8,36631
|
|
12
12
|
glide/async_commands/server_modules/ft.py,sha256=xOV22Znj9z9clKK5XZUL8UhthSbiA1F2H11EOKtMJCg,16840
|
|
@@ -16,13 +16,13 @@ glide/async_commands/server_modules/ft_options/ft_create_options.py,sha256=hz-H8
|
|
|
16
16
|
glide/async_commands/server_modules/ft_options/ft_profile_options.py,sha256=19t7pHHFu-Vbp_1e5XSNHHDjnssU4kI49wglE0YskDk,4273
|
|
17
17
|
glide/async_commands/server_modules/ft_options/ft_constants.py,sha256=r9uLAExg2qThjwOBC8LxqXBITF0fwa5xfnD7EXnyPrw,1704
|
|
18
18
|
glide/async_commands/stream.py,sha256=y3tmuOc-Ndnjvc__xybBcf2wqoNUQ1H1hPXYerpwNA8,15582
|
|
19
|
-
glide/async_commands/standalone_commands.py,sha256=
|
|
20
|
-
glide/async_commands/cluster_commands.py,sha256=
|
|
19
|
+
glide/async_commands/standalone_commands.py,sha256=vfqXTIU5YLMsHUD9MD3Qi1vccD9QMSQuH38mpo_5rjU,39510
|
|
20
|
+
glide/async_commands/cluster_commands.py,sha256=trG0vZCMZxrkziYBFlFvLZ3nMUvfS6r-BRkRwb9Gif0,61994
|
|
21
21
|
glide/async_commands/command_args.py,sha256=55vpSxeQr8wFU7olkFTEecl66wPk1g6vWxVYj16UvXs,2529
|
|
22
22
|
glide/async_commands/bitmap.py,sha256=ZHGLcKBP7RADtANqIR7PWdIW_gfDBFgpkIsQ-T4QFBQ,10125
|
|
23
23
|
glide/__init__.py,sha256=nCbDQf344sIuXbaCsivrjBjkQ3kaP_ArT3IQnzTUFx8,7372
|
|
24
24
|
glide/glide.pyi,sha256=K2CeC-F0E8vlr-rbko-E0PofzFoWl4da-xUQSuvuFDo,1105
|
|
25
|
-
glide/glide_client.py,sha256=
|
|
25
|
+
glide/glide_client.py,sha256=n9Vp7vjqRjHNK24YqHU35YkeDUriberJC5RPPS4_EeI,31870
|
|
26
26
|
glide/logger.py,sha256=IhlrmIDF4IufCOszQu2WnMZeyBfH21kVr8KwDlBqDP0,3800
|
|
27
27
|
glide/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
28
28
|
glide/exceptions.py,sha256=ZI_LwIduoR-1jHm9-6jWZkx90AqCJLRtjbv4iESIEEA,1194
|
|
@@ -32,6 +32,6 @@ glide/protobuf/command_request_pb2.py,sha256=Kl07aQBGu8i3oFqbT-uZByWVaTCjYuDeYb0
|
|
|
32
32
|
glide/protobuf/connection_request_pb2.py,sha256=rqnCM3pR4X74eEJzBFhsQ27SKxdtYI5vS-mbWFaQ7js,5706
|
|
33
33
|
glide/protobuf/command_request_pb2.pyi,sha256=DYnPAmwzyygCdCpW1R1CDGZB_O6zQRJp51K8Wr4CpFc,52470
|
|
34
34
|
glide/protobuf/response_pb2.py,sha256=r3_OFhf8HZvEmBSigSyBzG7S7kWl7CCgVMog4HgMFXM,2025
|
|
35
|
-
glide/routes.py,sha256=
|
|
36
|
-
glide/glide.cpython-311-darwin.so,sha256=
|
|
37
|
-
valkey_glide-2.0.
|
|
35
|
+
glide/routes.py,sha256=ZcLV_HrMzAYxHJW7uk905gdhOZbchBDSHlG1LVF7BJ4,4439
|
|
36
|
+
glide/glide.cpython-311-darwin.so,sha256=Awk81cX8i0nWX9qDZGLedkRfA_Iu3nvOYdWhPcliJdo,6642208
|
|
37
|
+
valkey_glide-2.0.0rc7.dist-info/RECORD,,
|
|
File without changes
|