lnbits-legend/lnbits/cache.py
dni ⚡ fe88320f08
[CHORE] update mypy and new issues (#1892)
* [CHORE] update mypy and new issues

lnbits/cache.py:21: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
lnbits/extension_manager.py:210: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
lnbits/db.py:110: error: Only instance methods can be decorated with @property  [misc]
lnbits/tasks.py:152: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
lnbits/tasks.py:171: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
lnbits/core/services.py:520: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
lnbits/app.py:520: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
lnbits/app.py:525: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]
lnbits/app.py:532: note: By default the bodies of untyped functions are not checked, consider using --check-untyped-defs  [annotation-unchecked]

* fix db.py
* fix mypy notes, type were not needed
2023-08-23 21:24:54 +02:00

66 lines
1.8 KiB
Python

from __future__ import annotations
import asyncio
from time import time
from typing import Any, NamedTuple, Optional
from loguru import logger
class Cached(NamedTuple):
value: Any
expiry: float
class Cache:
"""
Small caching utility providing simple get/set interface (very much like redis)
"""
def __init__(self) -> None:
self._values: dict[Any, Cached] = {}
def get(self, key: str, default=None) -> Optional[Any]:
cached = self._values.get(key)
if cached is not None:
if cached.expiry > time():
return cached.value
else:
self._values.pop(key)
return default
def set(self, key: str, value: Any, expiry: float = 10):
self._values[key] = Cached(value, time() + expiry)
def pop(self, key: str, default=None) -> Optional[Any]:
cached = self._values.pop(key, None)
if cached and cached.expiry > time():
return cached.value
return default
async def save_result(self, coro, key: str, expiry: float = 10):
"""
If `key` exists, return its value, otherwise call coro and cache its result
"""
cached = self.get(key)
if cached:
return cached
else:
value = await coro()
self.set(key, value, expiry=expiry)
return value
async def invalidate_forever(self, interval: float = 10):
while True:
try:
await asyncio.sleep(interval)
ts = time()
expired = [k for k, v in self._values.items() if v.expiry < ts]
for k in expired:
self._values.pop(k)
except Exception:
logger.error("Error invalidating cache")
cache = Cache()