aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar ks129 <[email protected]>2020-09-26 15:43:09 +0300
committerGravatar ks129 <[email protected]>2020-09-26 15:43:09 +0300
commitfd955f61447dc5401629a9312d4a86e3cbe68693 (patch)
treebeaf44d193db0013222aae0f1481c29ae154bbdc
parentMerge remote-tracking branch 'upstream/master' into pep-improvisations (diff)
Async Cache: Create class-based async cache
-rw-r--r--bot/exts/info/doc.py7
-rw-r--r--bot/exts/utils/utils.py5
-rw-r--r--bot/utils/cache.py49
3 files changed, 37 insertions, 24 deletions
diff --git a/bot/exts/info/doc.py b/bot/exts/info/doc.py
index 06dd4df63..ba443d817 100644
--- a/bot/exts/info/doc.py
+++ b/bot/exts/info/doc.py
@@ -22,7 +22,7 @@ from bot.bot import Bot
from bot.constants import MODERATION_ROLES, RedirectOutput
from bot.converters import ValidPythonIdentifier, ValidURL
from bot.pagination import LinePaginator
-from bot.utils.cache import async_cache
+from bot.utils.cache import AsyncCache
from bot.utils.messages import wait_for_deletion
@@ -66,6 +66,9 @@ WHITESPACE_AFTER_NEWLINES_RE = re.compile(r"(?<=\n\n)(\s+)")
FAILED_REQUEST_RETRY_AMOUNT = 3
NOT_FOUND_DELETE_DELAY = RedirectOutput.delete_delay
+# Async cache instance for docs cog
+async_cache = AsyncCache()
+
class DocMarkdownConverter(MarkdownConverter):
"""Subclass markdownify's MarkdownCoverter to provide custom conversion methods."""
@@ -187,7 +190,7 @@ class Doc(commands.Cog):
self.base_urls.clear()
self.inventories.clear()
self.renamed_symbols.clear()
- async_cache.cache["get_symbol_embed"] = OrderedDict()
+ async_cache.clear()
# Run all coroutines concurrently - since each of them performs a HTTP
# request, this speeds up fetching the inventory data heavily.
diff --git a/bot/exts/utils/utils.py b/bot/exts/utils/utils.py
index 2a74af172..64d42c93e 100644
--- a/bot/exts/utils/utils.py
+++ b/bot/exts/utils/utils.py
@@ -15,7 +15,7 @@ from bot.constants import Channels, MODERATION_ROLES, STAFF_ROLES
from bot.decorators import in_whitelist
from bot.pagination import LinePaginator
from bot.utils import messages
-from bot.utils.cache import async_cache
+from bot.utils.cache import AsyncCache
log = logging.getLogger(__name__)
@@ -43,6 +43,9 @@ Namespaces are one honking great idea -- let's do more of those!
ICON_URL = "https://www.python.org/static/opengraph-icon-200x200.png"
+# Async cache instance for PEPs
+async_cache = AsyncCache()
+
class Utils(Cog):
"""A selection of utilities which don't have a clear category."""
diff --git a/bot/utils/cache.py b/bot/utils/cache.py
index 37c2b199c..d8ec64ec8 100644
--- a/bot/utils/cache.py
+++ b/bot/utils/cache.py
@@ -3,7 +3,7 @@ from collections import OrderedDict
from typing import Any, Callable
-def async_cache(max_size: int = 128, arg_offset: int = 0) -> Callable:
+class AsyncCache:
"""
LRU cache implementation for coroutines.
@@ -11,23 +11,30 @@ def async_cache(max_size: int = 128, arg_offset: int = 0) -> Callable:
An offset may be optionally provided to be applied to the coroutine's arguments when creating the cache key.
"""
- # Make global cache as dictionary to allow multiple function caches
- async_cache.cache = {}
-
- def decorator(function: Callable) -> Callable:
- """Define the async_cache decorator."""
- async_cache.cache[function.__name__] = OrderedDict()
-
- @functools.wraps(function)
- async def wrapper(*args) -> Any:
- """Decorator wrapper for the caching logic."""
- key = ':'.join(str(args[arg_offset:]))
-
- if key not in async_cache.cache:
- if len(async_cache.cache[function.__name__]) > max_size:
- async_cache.cache[function.__name__].popitem(last=False)
-
- async_cache.cache[function.__name__][key] = await function(*args)
- return async_cache.cache[function.__name__][key]
- return wrapper
- return decorator
+
+ def __init__(self):
+ self._cache = OrderedDict()
+
+ def __call__(self, max_size: int = 128, arg_offset: int = 0) -> Callable:
+ """Decorator for async cache."""
+
+ def decorator(function: Callable) -> Callable:
+ """Define the async cache decorator."""
+
+ @functools.wraps(function)
+ async def wrapper(*args) -> Any:
+ """Decorator wrapper for the caching logic."""
+ key = ':'.join(str(args[arg_offset:]))
+
+ if key not in self._cache:
+ if len(self._cache) > max_size:
+ self._cache.popitem(last=False)
+
+ self._cache[key] = await function(*args)
+ return self._cache[key]
+ return wrapper
+ return decorator
+
+ def clear(self):
+ """Clear cache instance."""
+ self._cache.clear()