Skip to content

Commit

Permalink
Fix python example (valkey-io#1866)
Browse files Browse the repository at this point in the history
  • Loading branch information
barshaul authored Jul 9, 2024
1 parent 98053a8 commit eda6383
Show file tree
Hide file tree
Showing 5 changed files with 269 additions and 92 deletions.
4 changes: 2 additions & 2 deletions examples/python/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
## Run
To run the example or any other Python application utilizing Valkey GLIDE, activate the virtual environment that created by the 'Build' stage:
```
cd examples/python
pip install -r requirements.txt
python3 client_example.py
python3 standalone_example.py
python3 cluster_example.py
```
90 changes: 0 additions & 90 deletions examples/python/client_example.py

This file was deleted.

136 changes: 136 additions & 0 deletions examples/python/cluster_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import asyncio
from typing import List, Tuple

from glide import (
AllNodes,
ClosingError,
ConnectionError,
GlideClusterClient,
GlideClusterClientConfiguration,
InfoSection,
Logger,
LogLevel,
NodeAddress,
RequestError,
TimeoutError,
)


async def create_client(
nodes_list: List[Tuple[str, int]] = [("localhost", 6379)]
) -> GlideClusterClient:
"""
Creates and returns a GlideClusterClient instance.
This function initializes a GlideClusterClient with the provided list of nodes.
The nodes_list may contain the address of one or more cluster nodes, and the
client will automatically discover all nodes in the cluster.
Args:
nodes_list (List[Tuple[str, int]]): A list of tuples where each tuple
contains a host (str) and port (int). Defaults to [("localhost", 6379)].
Returns:
GlideClusterClient: An instance of GlideClusterClient connected to the discovered nodes.
"""
addresses = [NodeAddress(host, port) for host, port in nodes_list]
# Check `GlideClusterClientConfiguration` for additional options.
config = GlideClusterClientConfiguration(
addresses=addresses,
client_name="test_cluster_client",
# Enable this field if the servers are configured with TLS.
# use_tls=True
)
return await GlideClusterClient.create(config)


async def app_logic(client: GlideClusterClient):
"""
Executes the main logic of the application, performing basic operations
such as SET, GET, PING, and INFO REPLICATION using the provided GlideClusterClient.
Args:
client (GlideClusterClient): An instance of GlideClusterClient.
"""
# Send SET and GET
set_response = await client.set("foo", "bar")
Logger.log(LogLevel.INFO, "app", f"Set response is = {set_response!r}")

get_response = await client.get("foo")
assert isinstance(get_response, bytes)
Logger.log(LogLevel.INFO, "app", f"Get response is = {get_response.decode()!r}")

# Send PING to all primaries (according to Redis's PING request_policy)
pong = await client.ping()
Logger.log(LogLevel.INFO, "app", f"PING response is = {pong!r}")

# Send INFO REPLICATION with routing option to all nodes
info_repl_resps = await client.info([InfoSection.REPLICATION], AllNodes())
Logger.log(
LogLevel.INFO,
"app",
f"INFO REPLICATION responses from all nodes are=\n{info_repl_resps!r}",
)


async def exec_app_logic():
"""
Executes the application logic with exception handling.
"""
while True:
try:
client = await create_client()
return await app_logic(client)
except asyncio.CancelledError:
raise
except ClosingError as e:
# If the error message contains "NOAUTH", raise the exception
# because it indicates a critical authentication issue.
if "NOAUTH" in str(e):
Logger.log(
LogLevel.ERROR,
"glide",
f"Authentication error encountered: {e}",
)
raise e
Logger.log(
LogLevel.WARN,
"glide",
f"Client has closed and needs to be re-created: {e}",
)
except TimeoutError as e:
# A request timed out. You may choose to retry the execution based on your application's logic
Logger.log(LogLevel.ERROR, "glide", f"TimeoutError encountered: {e}")
raise e
except ConnectionError as e:
# The client wasn't able to reestablish the connection within the given retries
Logger.log(LogLevel.ERROR, "glide", f"ConnectionError encountered: {e}")
raise e
except RequestError as e:
# Other error reported during a request, such as a server response error
Logger.log(LogLevel.ERROR, "glide", f"RequestError encountered: {e}")
raise e
except Exception as e:
Logger.log(LogLevel.ERROR, "glide", f"Unexpected error: {e}")
raise e
finally:
try:
await client.close()
except Exception as e:
Logger.log(
LogLevel.WARN,
"glide",
f"Error encountered while closing the client: {e}",
)


def main():
# In this example, we will utilize the client's logger for all log messages
Logger.set_logger_config(LogLevel.INFO)
# Optional - set the logger to write to a file
# Logger.set_logger_config(LogLevel.INFO, file)
asyncio.run(exec_app_logic())


if __name__ == "__main__":
main()
129 changes: 129 additions & 0 deletions examples/python/standalone_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import asyncio
from typing import List, Tuple

from glide import (
ClosingError,
ConnectionError,
GlideClient,
GlideClientConfiguration,
Logger,
LogLevel,
NodeAddress,
RequestError,
TimeoutError,
)


async def create_client(
nodes_list: List[Tuple[str, int]] = [("localhost", 6379)]
) -> GlideClient:
"""
Creates and returns a GlideClient instance.
This function initializes a GlideClient with the provided list of nodes.
The nodes_list may contain either only primary node or a mix of primary
and replica nodes. The GlideClient use these nodes to connect to
the Standalone setup servers.
Args:
nodes_list (List[Tuple[str, int]]): A list of tuples where each tuple
contains a host (str) and port (int). Defaults to [("localhost", 6379)].
Returns:
GlideClient: An instance of GlideClient connected to the specified nodes.
"""
addresses = []
for host, port in nodes_list:
addresses.append(NodeAddress(host, port))

# Check `GlideClientConfiguration` for additional options.
config = GlideClientConfiguration(
addresses,
# Enable this field if the servers are configured with TLS.
# use_tls=True
)
return await GlideClient.create(config)


async def app_logic(client: GlideClient):
"""
Executes the main logic of the application, performing basic operations
such as SET, GET, and PING using the provided GlideClient.
Args:
client (GlideClient): An instance of GlideClient.
"""
# Send SET and GET
set_response = await client.set("foo", "bar")
Logger.log(LogLevel.INFO, "app", f"Set response is = {set_response!r}")

get_response = await client.get("foo")
assert isinstance(get_response, bytes)
Logger.log(LogLevel.INFO, "app", f"Get response is = {get_response.decode()!r}")

# Send PING to the primary node
pong = await client.ping()
Logger.log(LogLevel.INFO, "app", f"PING response is = {pong!r}")


async def exec_app_logic():
"""
Executes the application logic with exception handling.
"""
while True:
try:
client = await create_client()
return await app_logic(client)
except asyncio.CancelledError:
raise
except ClosingError as e:
# If the error message contains "NOAUTH", raise the exception
# because it indicates a critical authentication issue.
if "NOAUTH" in str(e):
Logger.log(
LogLevel.ERROR,
"glide",
f"Authentication error encountered: {e}",
)
raise e
Logger.log(
LogLevel.WARN,
"glide",
f"Client has closed and needs to be re-created: {e}",
)
except TimeoutError as e:
# A request timed out. You may choose to retry the execution based on your application's logic
Logger.log(LogLevel.ERROR, "glide", f"TimeoutError encountered: {e}")
raise e
except ConnectionError as e:
# The client wasn't able to reestablish the connection within the given retries
Logger.log(LogLevel.ERROR, "glide", f"ConnectionError encountered: {e}")
raise e
except RequestError as e:
# Other error reported during a request, such as a server response error
Logger.log(LogLevel.ERROR, "glide", f"RequestError encountered: {e}")
raise e
except Exception as e:
Logger.log(LogLevel.ERROR, "glide", f"Unexpected error: {e}")
raise e
finally:
try:
await client.close()
except Exception as e:
Logger.log(
LogLevel.WARN,
"glide",
f"Encountered an error while closing the client: {e}",
)


def main():
# In this example, we will utilize the client's logger for all log messages
Logger.set_logger_config(LogLevel.INFO)
# Optional - set the logger to write to a file
# Logger.set_logger_config(LogLevel.INFO, file)
asyncio.run(exec_app_logic())


if __name__ == "__main__":
main()
2 changes: 2 additions & 0 deletions python/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ Set response is OK
Get response is bar
```

For complete examples with error handling, please refer to the [cluster example](https://github.com/valkey-io/valkey-glide/blob/main/examples/python/cluster_example.py) and the [standalone example](https://github.com/valkey-io/valkey-glide/blob/main/examples/python/standalone_example.py).

## Documentation

Visit our [wiki](https://github.com/valkey-io/valkey-glide/wiki/Python-wrapper) for examples and further details on TLS, Read strategy, Timeouts and various other configurations.
Expand Down

0 comments on commit eda6383

Please sign in to comment.