Source code for edri.utility.storage
from random import choice
from string import ascii_letters, digits
from typing_extensions import LiteralString
__all__ = ["Storage"]
[docs]
class Storage[T](dict[str, T]):
"""
A generic storage class that extends a dictionary to hold items of any type,
identified by unique string keys. It provides functionality to automatically
generate unique keys for items if not provided.
:Type Parameters:
T: The type of the items to be stored in the dictionary.
:Examples:
>>> storage = Storage[int]()
>>> key1 = storage.append(100)
>>> key2 = storage.append(200, key="custom_key")
>>> storage[key1]
100
>>> storage["custom_key"]
200
:Note:
- The `Storage` class ensures that all keys are unique. If a key is not provided,
it automatically generates a unique key composed of random letters and digits.
- The default key length is 16 characters, but this can be customized during initialization.
"""
def __init__(
self,
choices: LiteralString = ascii_letters + digits,
length: int = 16,
) -> None:
"""
Initializes the storage with an empty dictionary and sets up key generation parameters.
:param choices: A string of characters to use for generating unique keys.
Defaults to a combination of ASCII letters and digits.
:type choices: LiteralString, optional
:param length: The length of the automatically generated unique keys.
Defaults to 16 characters.
:type length: int, optional
"""
super().__init__()
self.choices = choices
self.length = length
def _get_unique_key(self) -> str:
"""
Generates a unique key composed of random letters and digits.
This method repeatedly generates random keys until it finds one that is not
already present in the storage.
:return: A unique string key of specified length.
:rtype: str
:Examples:
>>> storage = Storage[int]()
>>> unique_key = storage._get_unique_key()
>>> len(unique_key)
16
>>> unique_key.isalnum()
True
"""
while True:
key = ''.join(choice(self.choices) for _ in range(self.length))
if key not in self:
return key
[docs]
def append(self, item: T, key: str | None = None) -> str:
"""
Adds an item to the storage with an automatically generated or specified key.
If the key already exists in the storage, a `KeyError` is raised to prevent
overwriting existing items.
:param item: The item to be stored.
:type item: T
:param key: The key under which to store the item. If `None`, a unique key
is generated automatically.
:type key: str, optional
:return: The key used to store the item in the dictionary.
:rtype: str
:raises KeyError: If the specified key already exists in the storage.
:Examples:
>>> storage = Storage[str]()
>>> generated_key = storage.append("apple")
>>> storage[generated_key]
'apple'
>>> custom_key = storage.append("banana", key="fruit_1")
>>> storage["fruit_1"]
'banana'
>>> storage.append("cherry", key="fruit_1")
Traceback (most recent call last):
...
KeyError: 'Key already exists: fruit_1'
"""
if key is None:
key = self._get_unique_key()
elif key in self:
raise KeyError(f"Key already exists: {key}")
self[key] = item
return key