Merge pull request 'v4.2.0' (#207) from dev into main
All checks were successful
Analysis / SonarCloud (push) Successful in 51s
Tests / Build and Test (3.11) (push) Successful in 1m11s
Tests / Build and Test (3.12) (push) Successful in 1m7s
Tests / Build and Test (3.13) (push) Successful in 1m6s
Upload Python Package / release-build (release) Successful in 21s
Upload Python Package / gitea-publish (release) Successful in 22s
Upload Python Package / pypi-publish (release) Successful in 13s
All checks were successful
Analysis / SonarCloud (push) Successful in 51s
Tests / Build and Test (3.11) (push) Successful in 1m11s
Tests / Build and Test (3.12) (push) Successful in 1m7s
Tests / Build and Test (3.13) (push) Successful in 1m6s
Upload Python Package / release-build (release) Successful in 21s
Upload Python Package / gitea-publish (release) Successful in 22s
Upload Python Package / pypi-publish (release) Successful in 13s
Reviewed-on: #207
This commit is contained in:
@@ -16,6 +16,7 @@ There are different sub-packages available:
|
||||
* pyrogram - Telegram bots with Pyrogram's fork "Pyrofork"
|
||||
* pycord - Discord bots with Pycord
|
||||
* speed - Performance improvements
|
||||
* cache - Support for Redis and Memcached
|
||||
* dev - Dependencies for package development purposes
|
||||
|
||||
You can freely choose any sub-package you want, as well as add multiple (comma-separated) or none at all.
|
||||
|
@@ -1,2 +1,2 @@
|
||||
aiofiles>=23.0.0
|
||||
typing-extensions~=4.12.2
|
||||
typing-extensions~=4.13.0
|
@@ -1,2 +1,2 @@
|
||||
pymemcache~=4.0.0
|
||||
redis~=5.2.1
|
||||
redis~=6.1.0
|
@@ -2,11 +2,11 @@ black==25.1.0
|
||||
build==1.2.2.post1
|
||||
isort==5.13.2
|
||||
mypy==1.15.0
|
||||
pylint==3.3.4
|
||||
pytest-asyncio==0.25.3
|
||||
pytest-cov==6.0.0
|
||||
pytest==8.3.4
|
||||
tox==4.24.0
|
||||
pylint==3.3.7
|
||||
pytest-asyncio==0.26.0
|
||||
pytest-cov==6.1.1
|
||||
pytest==8.3.5
|
||||
tox==4.26.0
|
||||
twine==6.1.0
|
||||
types-aiofiles==24.1.0.20241221
|
||||
types-ujson==5.10.0.20240515
|
||||
types-aiofiles==24.1.0.20250516
|
||||
types-ujson==5.10.0.20250326
|
@@ -1,4 +1,4 @@
|
||||
__version__ = "4.1.0"
|
||||
__version__ = "4.2.0"
|
||||
__license__ = "GPL3"
|
||||
__author__ = "Profitroll"
|
||||
|
||||
|
24
src/libbot/cache/classes/cache_memcached.py
vendored
24
src/libbot/cache/classes/cache_memcached.py
vendored
@@ -1,6 +1,6 @@
|
||||
import logging
|
||||
from logging import Logger
|
||||
from typing import Dict, Any
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
from pymemcache import Client
|
||||
|
||||
@@ -13,21 +13,27 @@ logger: Logger = logging.getLogger(__name__)
|
||||
class CacheMemcached(Cache):
|
||||
client: Client
|
||||
|
||||
def __init__(self, client: Client):
|
||||
self.client = client
|
||||
def __init__(self, client: Client, prefix: Optional[str] = None):
|
||||
self.client: Client = client
|
||||
self.prefix: str | None = prefix
|
||||
|
||||
logger.info("Initialized Memcached for caching")
|
||||
|
||||
@classmethod
|
||||
def from_config(cls, engine_config: Dict[str, Any]) -> "CacheMemcached":
|
||||
def from_config(cls, engine_config: Dict[str, Any], prefix: Optional[str] = None) -> "CacheMemcached":
|
||||
if "uri" not in engine_config:
|
||||
raise KeyError(
|
||||
"Cache configuration is invalid. Please check if all keys are set (engine: memcached)"
|
||||
)
|
||||
|
||||
return cls(Client(engine_config["uri"], default_noreply=True))
|
||||
return cls(Client(engine_config["uri"], default_noreply=True), prefix=prefix)
|
||||
|
||||
def _get_prefixed_key(self, key: str) -> str:
|
||||
return key if self.prefix is None else f"{self.prefix}_{key}"
|
||||
|
||||
def get_json(self, key: str) -> Any | None:
|
||||
key = self._get_prefixed_key(key)
|
||||
|
||||
try:
|
||||
result: Any | None = self.client.get(key, None)
|
||||
|
||||
@@ -43,6 +49,8 @@ class CacheMemcached(Cache):
|
||||
return None if result is None else _string_to_json(result)
|
||||
|
||||
def get_string(self, key: str) -> str | None:
|
||||
key = self._get_prefixed_key(key)
|
||||
|
||||
try:
|
||||
result: str | None = self.client.get(key, None)
|
||||
|
||||
@@ -62,6 +70,8 @@ class CacheMemcached(Cache):
|
||||
raise NotImplementedError()
|
||||
|
||||
def set_json(self, key: str, value: Any) -> None:
|
||||
key = self._get_prefixed_key(key)
|
||||
|
||||
try:
|
||||
self.client.set(key, _json_to_string(value))
|
||||
logger.debug("Set json cache key '%s'", key)
|
||||
@@ -70,6 +80,8 @@ class CacheMemcached(Cache):
|
||||
return None
|
||||
|
||||
def set_string(self, key: str, value: str) -> None:
|
||||
key = self._get_prefixed_key(key)
|
||||
|
||||
try:
|
||||
self.client.set(key, value)
|
||||
logger.debug("Set string cache key '%s'", key)
|
||||
@@ -82,6 +94,8 @@ class CacheMemcached(Cache):
|
||||
raise NotImplementedError()
|
||||
|
||||
def delete(self, key: str) -> None:
|
||||
key = self._get_prefixed_key(key)
|
||||
|
||||
try:
|
||||
self.client.delete(key)
|
||||
logger.debug("Deleted cache key '%s'", key)
|
||||
|
24
src/libbot/cache/classes/cache_redis.py
vendored
24
src/libbot/cache/classes/cache_redis.py
vendored
@@ -1,6 +1,6 @@
|
||||
import logging
|
||||
from logging import Logger
|
||||
from typing import Dict, Any
|
||||
from typing import Dict, Any, Optional
|
||||
|
||||
from redis import Redis
|
||||
|
||||
@@ -13,21 +13,27 @@ logger: Logger = logging.getLogger(__name__)
|
||||
class CacheRedis(Cache):
|
||||
client: Redis
|
||||
|
||||
def __init__(self, client: Redis):
|
||||
self.client = client
|
||||
def __init__(self, client: Redis, prefix: Optional[str] = None):
|
||||
self.client: Redis = client
|
||||
self.prefix: str | None = prefix
|
||||
|
||||
logger.info("Initialized Redis for caching")
|
||||
|
||||
@classmethod
|
||||
def from_config(cls, engine_config: Dict[str, Any]) -> Any:
|
||||
def from_config(cls, engine_config: Dict[str, Any], prefix: Optional[str] = None) -> Any:
|
||||
if "uri" not in engine_config:
|
||||
raise KeyError(
|
||||
"Cache configuration is invalid. Please check if all keys are set (engine: memcached)"
|
||||
)
|
||||
|
||||
return cls(Redis.from_url(engine_config["uri"]))
|
||||
return cls(Redis.from_url(engine_config["uri"]), prefix=prefix)
|
||||
|
||||
def _get_prefixed_key(self, key: str) -> str:
|
||||
return key if self.prefix is None else f"{self.prefix}_{key}"
|
||||
|
||||
def get_json(self, key: str) -> Any | None:
|
||||
key = self._get_prefixed_key(key)
|
||||
|
||||
try:
|
||||
result: Any | None = self.client.get(key)
|
||||
|
||||
@@ -43,6 +49,8 @@ class CacheRedis(Cache):
|
||||
return None if result is None else _string_to_json(result)
|
||||
|
||||
def get_string(self, key: str) -> str | None:
|
||||
key = self._get_prefixed_key(key)
|
||||
|
||||
try:
|
||||
result: str | None = self.client.get(key)
|
||||
|
||||
@@ -62,6 +70,8 @@ class CacheRedis(Cache):
|
||||
raise NotImplementedError()
|
||||
|
||||
def set_json(self, key: str, value: Any) -> None:
|
||||
key = self._get_prefixed_key(key)
|
||||
|
||||
try:
|
||||
self.client.set(key, _json_to_string(value))
|
||||
logger.debug("Set json cache key '%s'", key)
|
||||
@@ -70,6 +80,8 @@ class CacheRedis(Cache):
|
||||
return None
|
||||
|
||||
def set_string(self, key: str, value: str) -> None:
|
||||
key = self._get_prefixed_key(key)
|
||||
|
||||
try:
|
||||
self.client.set(key, value)
|
||||
logger.debug("Set string cache key '%s'", key)
|
||||
@@ -82,6 +94,8 @@ class CacheRedis(Cache):
|
||||
raise NotImplementedError()
|
||||
|
||||
def delete(self, key: str) -> None:
|
||||
key = self._get_prefixed_key(key)
|
||||
|
||||
try:
|
||||
self.client.delete(key)
|
||||
logger.debug("Deleted cache key '%s'", key)
|
||||
|
7
src/libbot/cache/manager/manager.py
vendored
7
src/libbot/cache/manager/manager.py
vendored
@@ -1,4 +1,4 @@
|
||||
from typing import Dict, Any, Literal
|
||||
from typing import Dict, Any, Literal, Optional
|
||||
|
||||
from ..classes import CacheMemcached, CacheRedis
|
||||
|
||||
@@ -6,6 +6,7 @@ from ..classes import CacheMemcached, CacheRedis
|
||||
def create_cache_client(
|
||||
config: Dict[str, Any],
|
||||
engine: Literal["memcached", "redis"] | None = None,
|
||||
prefix: Optional[str] = None,
|
||||
) -> CacheMemcached | CacheRedis:
|
||||
if engine not in ["memcached", "redis"] or engine is None:
|
||||
raise KeyError(f"Incorrect cache engine provided. Expected 'memcached' or 'redis', got '{engine}'")
|
||||
@@ -17,8 +18,8 @@ def create_cache_client(
|
||||
|
||||
match engine:
|
||||
case "memcached":
|
||||
return CacheMemcached.from_config(config["cache"][engine])
|
||||
return CacheMemcached.from_config(config["cache"][engine], prefix=prefix)
|
||||
case "redis":
|
||||
return CacheRedis.from_config(config["cache"][engine])
|
||||
return CacheRedis.from_config(config["cache"][engine], prefix=prefix)
|
||||
case _:
|
||||
raise KeyError(f"Cache implementation for the engine '{engine}' is not present.")
|
||||
|
Reference in New Issue
Block a user