diff options
| -rw-r--r-- | bot/utils/redis_cache.py | 37 | 
1 files changed, 27 insertions, 10 deletions
diff --git a/bot/utils/redis_cache.py b/bot/utils/redis_cache.py index d5563c079..e4dce7526 100644 --- a/bot/utils/redis_cache.py +++ b/bot/utils/redis_cache.py @@ -24,14 +24,6 @@ class RedisCache:      """      A simplified interface for a Redis connection. -    This class must be created as a class attribute in a class. This is because it -    uses __set_name__ to create a namespace like MyCog.my_class_attribute which is -    used as a hash name when we store stuff in Redis, to prevent collisions. - -    The class this object is instantiated in must also contains an attribute with an -    instance of Bot. This is because Bot contains our redis_pool, which is how this -    class communicates with the Redis server. -      We implement several convenient methods that are fairly similar to have a dict      behaves, and should be familiar to Python users. The biggest difference is that      all the public methods in this class are coroutines, and must be awaited. @@ -39,6 +31,10 @@ class RedisCache:      Because of limitations in Redis, this cache will only accept strings, integers and      floats both for keys and values. +    Please note that this class MUST be created as a class attribute, and that that class +    must also contain an attribute with an instance of our Bot. See `__get__` and `__set_name__` +    for more information about how this works. +      Simple example for how to use this:      class SomeCog(Cog): @@ -78,12 +74,18 @@ class RedisCache:      _namespaces = []      def __init__(self) -> None: -        """Raise a NotImplementedError if `__set_name__` hasn't been run.""" +        """Initialize the RedisCache."""          self._namespace = None          self.bot = None      def _set_namespace(self, namespace: str) -> None:          """Try to set the namespace, but do not permit collisions.""" +        # We need a unique namespace, to prevent collisions. This loop +        # will try appending underscores to the end of the namespace until +        # it finds one that is unique. +        # +        # For example, if `john` and `john_`  are both taken, the namespace will +        # be `john__` at the end of this loop.          while namespace in self._namespaces:              namespace += "_" @@ -136,11 +138,26 @@ class RedisCache:          Set the namespace to Class.attribute_name.          Called automatically when this class is constructed inside a class as an attribute. + +        This class MUST be created as a class attribute in a class, otherwise it will raise +        exceptions whenever a method is used. This is because it uses this method to create +        a namespace like `MyCog.my_class_attribute` which is used as a hash name when we store +        stuff in Redis, to prevent collisions.          """          self._set_namespace(f"{owner.__name__}.{attribute_name}")      def __get__(self, instance: RedisCache, owner: Any) -> RedisCache: -        """Fetch the Bot instance, we need it for the redis pool.""" +        """ +        This is called if the RedisCache is a class attribute, and is accessed. + +        The class this object is instantiated in must contain an attribute with an +        instance of Bot. This is because Bot contains our redis_session, which is +        the mechanism by which we will communicate with the Redis server. + +        Any attempt to use RedisCache in a class that does not have a Bot instance +        will fail. It is mostly intended to be used inside of a Cog, although theoretically +        it should work in any class that has a Bot instance. +        """          if self.bot:              return self  |