Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 46 additions & 4 deletions src/momento/cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@

class Cache:
def __init__(self, auth_token, cache_name, endpoint, default_ttlSeconds):
"""Initializes Cache to perform gets and sets.

Args:
auth_token: Momento JWT token.
cache_name: Name of the cache
end_point: String of endpoint to reach Momento Cache
default_ttlSeconds: Time (in seconds) for which an item will be stored in the cache.
"""
self._validate_ttl(default_ttlSeconds)
self._default_ttlSeconds = default_ttlSeconds
self._secure_channel = grpc.secure_channel(
Expand All @@ -27,11 +35,15 @@ def __init__(self, auth_token, cache_name, endpoint, default_ttlSeconds):
cache_interceptor)
self._client = cache_client.ScsStub(intercept_channel)

# While the constructor opens the grpc channel. Connect allows the channel
# to test the connection with provided cache name and auth token.
# Separating the _connect from the constructor, allows better latency and
# resource management for calls that need get or create functionality.

def _connect(self) :
"""Connects the cache to backend.

While the constructor opens the grpc channel. Connect allows the channel
to test the connection with provided cache name and auth token.
Separating the _connect from the constructor, allows better latency and
resource management for calls that need get or create functionality.
"""
try:
_momento_logger.debug('Initializing connection with Cache Service')
self.get(uuid.uuid1().bytes)
Expand All @@ -48,6 +60,22 @@ def __exit__(self, exc_type, exc_value, exc_traceback):
self._secure_channel.close()

def set(self, key, value, ttl_seconds=None):
"""Stores an item in cache

Args:
key (string or bytes): The key to be used to store item in the cache.
value (string or bytes): The value to be used to store item in the cache.
ttl_second (Optional): Time to live in cache in seconds. If not provided default TTL provided while creating the cache client instance is used.

Returns:
CacheSetResponse

Raises:
CacheValueError: If service validation fails for provided values.
CacheNotFoundError: If an attempt is made to store an item in a cache that doesn't exist.
PermissionError: If the provided Momento Auth Token is invalid to perform the requested operation.
InternalServerError: If server encountered an unknown error while trying to store the item.
"""
try:
_momento_logger.debug(f'Issuing a set request with key {key}')
item_ttl_seconds = self._default_ttlSeconds if ttl_seconds is None else ttl_seconds
Expand All @@ -67,6 +95,20 @@ def set(self, key, value, ttl_seconds=None):
raise _cache_service_errors_converter.convert(e)

def get(self, key):
"""Retrieve an item from the cache

Args:
key (string or bytes): The key to be used to retrieve item from the cache.

Returns:
CacheGetResponse

Raises:
CacheValueError: If service validation fails for provided values.
CacheNotFoundError: If an attempt is made to retrieve an item in a cache that doesn't exist.
PermissionError: If the provided Momento Auth Token is invalid to perform the requested operation.
InternalServerError: If server encountered an unknown error while trying to retrieve the item.
"""
try:
_momento_logger.debug(f'Issuing a get request with key {key}')
get_request = cache_client_types.GetRequest()
Expand Down
39 changes: 37 additions & 2 deletions src/momento/cache_operation_responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,40 @@ class CacheResult(Enum):

class CacheSetResponse:
def __init__(self, grpc_set_response, value):
"""Initializes CacheSetResponse to handle gRPC set response.

Args:
grpc_set_response: Protobuf based response returned by Scs.
value (string or bytes): The value to be used to store item in the cache

Raises:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I doubt if all these errors will be thrown. Can you verify? All I think will come on initialize is InternalServerError from call to error_converter.convert_ecache_result

InternalServerError: If server encountered an unknown error while trying to store the item.
"""
self._value = value
if (grpc_set_response.result != cache_client_types.Ok):
_momento_logger.debug(f'Set received unsupported ECacheResult {grpc_set_response.result}')
raise error_converter.convert_ecache_result(
grpc_set_response.result, grpc_set_response.message, 'SET')

def str_utf8(self):
"""Decodes string value set in cache to a utf-8 string."""
return self._value.decode('utf-8')

def bytes(self):
"""Returns byte value set in cache."""
return self._value


class CacheGetResponse:
def __init__(self, grpc_get_response):
"""Initializes CacheGetResponse to handle gRPC get response.

Args:
grpc_get_response: Protobuf based response returned by Scs.

Raises:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ditto: please verify if these errors will ever come from this method.

InternalServerError: If server encountered an unknown error while trying to retrieve the item.
"""
self._value = grpc_get_response.cache_body

if (grpc_get_response.result == cache_client_types.Hit):
Expand All @@ -39,16 +58,19 @@ def __init__(self, grpc_get_response):


def str_utf8(self):
"""Returns value stored in cache as utf-8 string if there was Hit. Returns None otherwise."""
if (self._result == CacheResult.HIT):
return self._value.decode('utf-8')
return None

def bytes(self):
"""Returns value stored in cache as bytes if there was Hit. Returns None otherwise."""
if (self._result == CacheResult.HIT):
return self._value
return None

def result(self):
"""Returns get operation result such as HIT or MISS."""
return self._result


Expand All @@ -64,21 +86,34 @@ def __init__(self, grpc_delete_cache_response):

class ListCachesResponse:
def __init__(self, grpc_list_cache_response):
"""Initializes ListCacheResponse to handle list cache response.

Args:
grpc_list_cache_response: Protobuf based response returned by Scs.
"""
self._next_token = grpc_list_cache_response.next_token if grpc_list_cache_response.next_token != '' else None
self._caches = []
for cache in grpc_list_cache_response.cache:
self._caches.append(CacheInfo(cache))

def next_token(self):
"""Returns next token."""
return self._next_token

def caches(self):
"""Returns all caches."""
return self._caches


class CacheInfo:
def __init__(self, grpc_listed_caches):
self._name = grpc_listed_caches.cache_name
def __init__(self, grpc_listed_cache):
"""Initializes CacheInfo to handle caches returned from list cache operation.

Args:
grpc_listed_cache: Protobuf based response returned by Scs.
"""
self._name = grpc_listed_cache.cache_name

def name(self):
"""Returns all cache's name."""
return self._name
54 changes: 54 additions & 0 deletions src/momento/momento.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,12 @@

class Momento:
def __init__(self, auth_token, endpoint_override=None):
"""Initializes Momento to setup SCS client.

Args:
auth_token: Momento JWT
endpoint_override: String of optional endpoint override to be used when given an explicit endpoint by the Momneto team
"""
endpoints = _momento_endpoint_resolver.resolve(auth_token,
endpoint_override)
self._auth_token = auth_token
Expand All @@ -36,6 +42,17 @@ def __exit__(self, exc_type, exc_value, exc_traceback):
self._secure_channel.close()

def create_cache(self, cache_name):
"""Creates a new cache in your Momento account.

Args:
cache_name: String used to create cache.

Returns:
CreateCacheResponse

Raises:
ClientSdkError: If an attempt is made to pass anything other than string as cache_name.
"""
try:
_momento_logger.debug(f'Creating cache with name: {cache_name}')
request = CreateCacheRequest()
Expand All @@ -46,6 +63,18 @@ def create_cache(self, cache_name):
raise _cache_service_errors_converter.convert(e) from None

def delete_cache(self, cache_name):
"""Deletes a cache and all of the items within it.

Args:
cache_name: String cache name to delete.

Returns:
DeleteCacheResponse

Raises:
CacheNotFoundError: If an attempt is made to delete a MomentoCache that doesn't exits.
ClientSdkError: If an attempt is made to pass anything other than string as cache_name.
"""
try:
_momento_logger.debug(f'Deleting cache with name: {cache_name}')
request = DeleteCacheRequest()
Expand All @@ -56,6 +85,20 @@ def delete_cache(self, cache_name):
raise _cache_service_errors_converter.convert(e) from None

def get_cache(self, cache_name, ttl_seconds, create_if_absent=False):
"""Gets a MomentoCache to perform gets and sets on.

Args:
cache_name: String cache name
ttl_seconds: Time to live if object insdie of cache in seconds.
create_if_absent: Boolean value to decide if cache should be created if it does not exist.

Returns:
Cache

Raises:
CacheNotFoundError: If an attempt is made to get a MomentoCache that doesn't exits.
ClientSdkError: If an attempt is made to pass anything other than string as cache_name.
"""
cache = Cache(self._auth_token, cache_name, self._cache_endpoint,
ttl_seconds)
try:
Expand All @@ -69,6 +112,17 @@ def get_cache(self, cache_name, ttl_seconds, create_if_absent=False):
return cache._connect()

def list_caches(self, next_token=None):
"""Lists all caches.

Args:
next_token: Token to continue paginating through the list. It's used to handle large paginated lists.

Returns:
ListCachesResponse

Raises:
Exception to notify either sdk, grpc, or operation error.
"""
try:
list_caches_request = ListCachesRequest()
list_caches_request.next_token = next_token if next_token is not None else ''
Expand Down