Skip to content

Commit

Permalink
Python: Move python commands to bytes string (valkey-io#1742)
Browse files Browse the repository at this point in the history
---------

Co-authored-by: Shoham Elias <[email protected]>
  • Loading branch information
GilboaAWS and shohamazon authored Jul 2, 2024
1 parent 8aae567 commit 757c679
Show file tree
Hide file tree
Showing 13 changed files with 2,397 additions and 2,068 deletions.
4 changes: 2 additions & 2 deletions examples/python/client_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ def set_file_logger(level: LogLevel = LogLevel.WARN, file: Optional[str] = None)

async def send_set_and_get(client: Union[GlideClient, GlideClusterClient]):
set_response = await client.set("foo", "bar")
print(f"Set response is = {set_response}")
print(f"Set response is = {set_response!r}")
get_response = await client.get("foo")
print(f"Get response is = {get_response}")
print(f"Get response is = {get_response!r}")


async def test_standalone_client(host: str = "localhost", port: int = 6379):
Expand Down
290 changes: 154 additions & 136 deletions python/python/glide/async_commands/cluster_commands.py

Large diffs are not rendered by default.

1,940 changes: 1,013 additions & 927 deletions python/python/glide/async_commands/core.py

Large diffs are not rendered by default.

68 changes: 34 additions & 34 deletions python/python/glide/async_commands/redis_modules/json.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
'OK' # Indicates successful setting of the value at path '$' in the key stored at `doc`.
>>> json_get = await redisJson.get(client, "doc", "$") # Returns the value at path '$' in the JSON document stored at `doc` as JSON string.
>>> print(json_get)
"[{\"a\":1.0,\"b\":2}]"
>>> json.loads(json_get)
b"[{\"a\":1.0,\"b\":2}]"
>>> json.loads(str(json_get))
[{"a": 1.0, "b" :2}] # JSON object retrieved from the key `doc` using json.loads()
"""
from typing import List, Optional, Union, cast

from glide.async_commands.core import ConditionalChange
from glide.constants import TOK, TJsonResponse
from glide.constants import TOK, TEncodable, TJsonResponse
from glide.glide_client import TGlideClient
from glide.protobuf.redis_request_pb2 import RequestType

Expand Down Expand Up @@ -56,9 +56,9 @@ def get_options(self) -> List[str]:

async def set(
client: TGlideClient,
key: str,
path: str,
value: str,
key: TEncodable,
path: TEncodable,
value: TEncodable,
set_condition: Optional[ConditionalChange] = None,
) -> Optional[TOK]:
"""
Expand All @@ -68,10 +68,10 @@ async def set(
Args:
client (TGlideClient): The Redis client to execute the command.
key (str): The key of the JSON document.
path (str): Represents the path within the JSON document where the value will be set.
key (TEncodable): The key of the JSON document.
path (TEncodable): Represents the path within the JSON document where the value will be set.
The key will be modified only if `value` is added as the last child in the specified `path`, or if the specified `path` acts as the parent of a new child being added.
value (set): The value to set at the specific path, in JSON formatted str.
value (TEncodable): The value to set at the specific path, in JSON formatted bytes or str.
set_condition (Optional[ConditionalChange]): Set the value only if the given condition is met (within the key or path).
Equivalent to [`XX` | `NX`] in the Redis API. Defaults to None.
Expand All @@ -96,53 +96,53 @@ async def set(

async def get(
client: TGlideClient,
key: str,
paths: Optional[Union[str, List[str]]] = None,
key: TEncodable,
paths: Optional[Union[TEncodable, List[TEncodable]]] = None,
options: Optional[JsonGetOptions] = None,
) -> Optional[str]:
) -> Optional[bytes]:
"""
Retrieves the JSON value at the specified `paths` stored at `key`.
See https://redis.io/commands/json.get/ for more details.
Args:
client (TGlideClient): The Redis client to execute the command.
key (str): The key of the JSON document.
paths (Optional[Union[str, List[str]]]): The path or list of paths within the JSON document. Default is root `$`.
options (Optional[JsonGetOptions]): Options for formatting the string representation of the JSON data. See `JsonGetOptions`.
key (TEncodable): The key of the JSON document.
paths (Optional[Union[TEncodable, List[TEncodable]]]): The path or list of paths within the JSON document. Default is root `$`.
options (Optional[JsonGetOptions]): Options for formatting the byte representation of the JSON data. See `JsonGetOptions`.
Returns:
str: A bulk string representation of the returned value.
bytes: A bytes representation of the returned value.
If `key` doesn't exists, returns None.
Examples:
>>> from glide import json as redisJson
>>> import json
>>> json_str = await redisJson.get(client, "doc", "$")
>>> json.loads(json_str) # Parse JSON string to Python data
>>> json.loads(str(json_str)) # Parse JSON string to Python data
[{"a": 1.0, "b" :2}] # JSON object retrieved from the key `doc` using json.loads()
>>> await redisJson.get(client, "doc", "$")
"[{\"a\":1.0,\"b\":2}]" # Returns the value at path '$' in the JSON document stored at `doc`.
b"[{\"a\":1.0,\"b\":2}]" # Returns the value at path '$' in the JSON document stored at `doc`.
>>> await redisJson.get(client, "doc", ["$.a", "$.b"], json.JsonGetOptions(indent=" ", newline="\n", space=" "))
"{\n \"$.a\": [\n 1.0\n ],\n \"$.b\": [\n 2\n ]\n}" # Returns the values at paths '$.a' and '$.b' in the JSON document stored at `doc`, with specified formatting options.
b"{\n \"$.a\": [\n 1.0\n ],\n \"$.b\": [\n 2\n ]\n}" # Returns the values at paths '$.a' and '$.b' in the JSON document stored at `doc`, with specified formatting options.
>>> await redisJson.get(client, "doc", "$.non_existing_path")
"[]" # Returns an empty array since the path '$.non_existing_path' does not exist in the JSON document stored at `doc`.
b"[]" # Returns an empty array since the path '$.non_existing_path' does not exist in the JSON document stored at `doc`.
"""
args = ["JSON.GET", key]
if options:
args.extend(options.get_options())
if paths:
if isinstance(paths, str):
if isinstance(paths, (str, bytes)):
paths = [paths]
args.extend(paths)

return cast(str, await client.custom_command(args))
return cast(bytes, await client.custom_command(args))


async def delete(
client: TGlideClient,
key: str,
path: Optional[str] = None,
key: TEncodable,
path: Optional[TEncodable] = None,
) -> int:
"""
Deletes the JSON value at the specified `path` within the JSON document stored at `key`.
Expand All @@ -151,8 +151,8 @@ async def delete(
Args:
client (TGlideClient): The Redis client to execute the command.
key (str): The key of the JSON document.
path (Optional[str]): Represents the path within the JSON document where the value will be deleted.
key (TEncodable): The key of the JSON document.
path (Optional[TEncodable]): Represents the path within the JSON document where the value will be deleted.
If None, deletes the entire JSON document at `key`. Defaults to None.
Returns:
Expand All @@ -178,8 +178,8 @@ async def delete(

async def forget(
client: TGlideClient,
key: str,
path: Optional[str] = None,
key: TEncodable,
path: Optional[TEncodable] = None,
) -> Optional[int]:
"""
Deletes the JSON value at the specified `path` within the JSON document stored at `key`.
Expand All @@ -188,8 +188,8 @@ async def forget(
Args:
client (TGlideClient): The Redis client to execute the command.
key (str): The key of the JSON document.
path (Optional[str]): Represents the path within the JSON document where the value will be deleted.
key (TEncodable): The key of the JSON document.
path (Optional[TEncodable]): Represents the path within the JSON document where the value will be deleted.
If None, deletes the entire JSON document at `key`. Defaults to None.
Returns:
Expand All @@ -216,8 +216,8 @@ async def forget(

async def toggle(
client: TGlideClient,
key: str,
path: str,
key: TEncodable,
path: TEncodable,
) -> TJsonResponse[bool]:
"""
Toggles a Boolean value stored at the specified `path` within the JSON document stored at `key`.
Expand All @@ -226,8 +226,8 @@ async def toggle(
Args:
client (TGlideClient): The Redis client to execute the command.
key (str): The key of the JSON document.
path (str): The JSONPath to specify.
key (TEncodable): The key of the JSON document.
path (TEncodable): The JSONPath to specify.
Returns:
TJsonResponse[bool]: For JSONPath (`path` starts with `$`), returns a list of boolean replies for every possible path, with the toggled boolean value,
Expand Down
68 changes: 37 additions & 31 deletions python/python/glide/async_commands/sorted_set.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Copyright Valkey GLIDE Project Contributors - SPDX Identifier: Apache-2.0

from enum import Enum
from typing import List, Optional, Tuple, Union
from typing import List, Optional, Tuple, Union, cast

from glide.async_commands.command_args import Limit, OrderBy
from glide.constants import TEncodable


class InfBound(Enum):
Expand Down Expand Up @@ -278,12 +279,12 @@ def to_args(self) -> List[str]:


def _create_zrange_args(
key: str,
key: TEncodable,
range_query: Union[RangeByLex, RangeByScore, RangeByIndex],
reverse: bool,
with_scores: bool,
destination: Optional[str] = None,
) -> List[str]:
destination: Optional[TEncodable] = None,
) -> List[TEncodable]:
args = [destination] if destination else []
args += [key, str(range_query.start), str(range_query.stop)]

Expand All @@ -308,32 +309,35 @@ def _create_zrange_args(


def separate_keys(
keys: Union[List[str], List[Tuple[str, float]]]
) -> Tuple[List[str], List[str]]:
keys: Union[List[TEncodable], List[Tuple[TEncodable, float]]]
) -> Tuple[List[TEncodable], List[TEncodable]]:
"""
Returns seperate lists of keys and weights in case of weighted keys.
Returns separate lists of keys and weights in case of weighted keys.
"""
if not keys:
return [], []

key_list: List[str] = []
weight_list: List[str] = []
key_list: List[TEncodable] = []
weight_list: List[TEncodable] = []

if isinstance(keys[0], tuple):
key_list = [item[0] for item in keys]
weight_list = [str(item[1]) for item in keys]
for item in keys:
key = item[0]
weight = item[1]
key_list.append(cast(TEncodable, key))
weight_list.append(cast(TEncodable, str(weight)))
else:
key_list = keys # type: ignore
key_list.extend(cast(List[TEncodable], keys))

return key_list, weight_list


def _create_zinter_zunion_cmd_args(
keys: Union[List[str], List[Tuple[str, float]]],
keys: Union[List[TEncodable], List[Tuple[TEncodable, float]]],
aggregation_type: Optional[AggregationType] = None,
destination: Optional[str] = None,
) -> List[str]:
args = []
destination: Optional[TEncodable] = None,
) -> List[TEncodable]:
args: List[TEncodable] = []

if destination:
args.append(destination)
Expand All @@ -342,11 +346,11 @@ def _create_zinter_zunion_cmd_args(

only_keys, weights = separate_keys(keys)

args += only_keys
args.extend(only_keys)

if weights:
args.append("WEIGHTS")
args += weights
args.extend(weights)

if aggregation_type:
args.append("AGGREGATE")
Expand All @@ -356,27 +360,29 @@ def _create_zinter_zunion_cmd_args(


def _create_geosearch_args(
keys: List[str],
search_from: Union[str, GeospatialData],
seach_by: Union[GeoSearchByRadius, GeoSearchByBox],
keys: List[TEncodable],
search_from: Union[str, bytes, GeospatialData],
search_by: Union[GeoSearchByRadius, GeoSearchByBox],
order_by: Optional[OrderBy] = None,
count: Optional[GeoSearchCount] = None,
with_coord: bool = False,
with_dist: bool = False,
with_hash: bool = False,
store_dist: bool = False,
) -> List[str]:
args = keys
if isinstance(search_from, str):
args += ["FROMMEMBER", search_from]
) -> List[TEncodable]:
args: List[TEncodable] = keys
if isinstance(search_from, str | bytes):
args.extend(["FROMMEMBER", search_from])
else:
args += [
"FROMLONLAT",
str(search_from.longitude),
str(search_from.latitude),
]
args.extend(
[
"FROMLONLAT",
str(search_from.longitude),
str(search_from.latitude),
]
)

args += seach_by.to_args()
args.extend(search_by.to_args())

if order_by:
args.append(order_by.value)
Expand Down
Loading

0 comments on commit 757c679

Please sign in to comment.