Compare commits

...

38 Commits

Author SHA1 Message Date
1daed542a3 Merge pull request 'v4.3.0' (#220) from dev into main
All checks were successful
Analysis / SonarCloud (push) Successful in 1m0s
Tests / Build and Test (3.11) (push) Successful in 1m23s
Tests / Build and Test (3.12) (push) Successful in 1m20s
Tests / Build and Test (3.13) (push) Successful in 1m11s
Upload Python Package / release-build (release) Successful in 26s
Upload Python Package / gitea-publish (release) Successful in 14s
Upload Python Package / pypi-publish (release) Successful in 15s
Reviewed-on: #220
2025-07-08 01:34:43 +03:00
e4ce5976f2 Changed default cache TTL to 0 and None for memcached and redis respectively
All checks were successful
Analysis / SonarCloud (push) Successful in 50s
Analysis / SonarCloud (pull_request) Successful in 52s
Tests / Build and Test (3.11) (pull_request) Successful in 1m14s
Tests / Build and Test (3.12) (pull_request) Successful in 1m20s
Tests / Build and Test (3.13) (pull_request) Successful in 1m18s
2025-07-08 00:01:14 +02:00
32a9e14d0c Added a default TTL of 300 seconds for cache entries (#219)
All checks were successful
Analysis / SonarCloud (push) Successful in 50s
Analysis / SonarCloud (pull_request) Successful in 1m4s
Tests / Build and Test (3.11) (pull_request) Successful in 1m14s
Tests / Build and Test (3.12) (pull_request) Successful in 1m15s
Tests / Build and Test (3.13) (pull_request) Successful in 1m19s
2025-07-07 23:47:55 +02:00
3110bb64b1 Closes #219
All checks were successful
Analysis / SonarCloud (push) Successful in 1m35s
2025-07-07 23:35:21 +02:00
ad38dbdca1 Update dependency pytest to v8.4.1
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 50s
Tests / Build and Test (3.11) (pull_request) Successful in 1m17s
Tests / Build and Test (3.12) (pull_request) Successful in 1m15s
Tests / Build and Test (3.13) (pull_request) Successful in 1m9s
Analysis / SonarCloud (push) Successful in 50s
2025-06-18 09:21:02 +03:00
edc3e0717d Update dependency tox to v4.27.0
All checks were successful
Tests / Build and Test (3.11) (pull_request) Successful in 1m22s
Tests / Build and Test (3.12) (pull_request) Successful in 1m30s
Tests / Build and Test (3.13) (pull_request) Successful in 1m40s
Analysis / SonarCloud (push) Successful in 1m1s
Analysis / SonarCloud (pull_request) Successful in 58s
2025-06-17 18:51:05 +03:00
d70fd4f491 Update dependency mypy to v1.16.1
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 58s
Tests / Build and Test (3.11) (pull_request) Successful in 1m17s
Tests / Build and Test (3.12) (pull_request) Successful in 1m16s
Tests / Build and Test (3.13) (pull_request) Successful in 1m10s
Analysis / SonarCloud (push) Successful in 1m9s
2025-06-16 20:06:16 +03:00
c4fb1dd5dd Update dependency pytest-cov to v6.2.1
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 53s
Tests / Build and Test (3.11) (pull_request) Successful in 1m20s
Tests / Build and Test (3.12) (pull_request) Successful in 1m19s
Tests / Build and Test (3.13) (pull_request) Successful in 1m12s
Analysis / SonarCloud (push) Successful in 1m1s
2025-06-12 13:57:08 +03:00
38bf43a5e7 Update dependency pytest-cov to v6.2.0
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 50s
Tests / Build and Test (3.11) (pull_request) Successful in 1m24s
Tests / Build and Test (3.12) (pull_request) Successful in 1m34s
Tests / Build and Test (3.13) (pull_request) Successful in 1m11s
Analysis / SonarCloud (push) Successful in 49s
2025-06-12 01:32:32 +03:00
5dff5fa71d Update dependency types-aiofiles to v24.1.0.20250606
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 49s
Tests / Build and Test (3.11) (pull_request) Successful in 1m14s
Tests / Build and Test (3.12) (pull_request) Successful in 1m10s
Tests / Build and Test (3.13) (pull_request) Successful in 1m8s
Analysis / SonarCloud (push) Successful in 50s
2025-06-06 06:11:29 +03:00
e596658c68 Update dependency pytest to v8.4.0
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 58s
Tests / Build and Test (3.11) (pull_request) Successful in 1m11s
Tests / Build and Test (3.12) (pull_request) Successful in 1m8s
Tests / Build and Test (3.13) (pull_request) Successful in 1m6s
Analysis / SonarCloud (push) Successful in 51s
2025-06-02 20:43:25 +03:00
1e1b04a8ff Update dependency typing-extensions to ~=4.14.0
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 58s
Tests / Build and Test (3.11) (pull_request) Successful in 1m19s
Tests / Build and Test (3.12) (pull_request) Successful in 1m11s
Tests / Build and Test (3.13) (pull_request) Successful in 1m9s
Analysis / SonarCloud (push) Successful in 1m7s
2025-06-02 18:39:15 +03:00
69b034c007 Update dependency mypy to v1.16.0
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 46s
Tests / Build and Test (3.11) (pull_request) Successful in 1m17s
Tests / Build and Test (3.12) (pull_request) Successful in 1m10s
Tests / Build and Test (3.13) (pull_request) Successful in 1m7s
Analysis / SonarCloud (push) Successful in 51s
2025-05-29 16:49:31 +03:00
kku
54de950899 Fixed compatibility issue with PEP 639
All checks were successful
Analysis / SonarCloud (push) Successful in 51s
2025-05-28 10:05:30 +02:00
c17a206c44 Update dependency redis to ~=6.2.0
Some checks failed
Analysis / SonarCloud (pull_request) Successful in 48s
Tests / Build and Test (3.11) (pull_request) Failing after 55s
Tests / Build and Test (3.12) (pull_request) Successful in 1m7s
Tests / Build and Test (3.13) (pull_request) Successful in 1m8s
Analysis / SonarCloud (push) Successful in 50s
2025-05-28 08:54:30 +03:00
dc05eb0ccb Update dependency pytest-asyncio to v1
Some checks failed
Analysis / SonarCloud (pull_request) Successful in 50s
Tests / Build and Test (3.11) (pull_request) Failing after 52s
Tests / Build and Test (3.12) (pull_request) Successful in 1m20s
Tests / Build and Test (3.13) (pull_request) Successful in 1m20s
Analysis / SonarCloud (push) Successful in 50s
2025-05-26 08:33:47 +03:00
3a7f748d96 Updated the license specification to comply with PEP 639
All checks were successful
Analysis / SonarCloud (push) Successful in 47s
2025-05-18 17:44:18 +02:00
af74e3fdd0 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
Reviewed-on: #207
2025-05-18 18:38:49 +03:00
95abf4265c Added support for cache prefix
All checks were successful
Analysis / SonarCloud (push) Successful in 54s
Analysis / SonarCloud (pull_request) Successful in 46s
Tests / Build and Test (3.11) (pull_request) Successful in 1m12s
Tests / Build and Test (3.12) (pull_request) Successful in 1m9s
Tests / Build and Test (3.13) (pull_request) Successful in 1m6s
2025-05-18 17:29:27 +02:00
84e1cf7ce9 Update dependency types-aiofiles to v24.1.0.20250516
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 41s
Tests / Build and Test (3.11) (pull_request) Successful in 1m9s
Tests / Build and Test (3.12) (pull_request) Successful in 1m9s
Tests / Build and Test (3.13) (pull_request) Successful in 1m7s
Analysis / SonarCloud (push) Successful in 48s
2025-05-16 06:49:57 +03:00
accd22dd4d Update dependency tox to v4.26.0
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 43s
Tests / Build and Test (3.11) (pull_request) Successful in 1m9s
Tests / Build and Test (3.12) (pull_request) Successful in 1m7s
Tests / Build and Test (3.13) (pull_request) Successful in 1m4s
Analysis / SonarCloud (push) Successful in 46s
2025-05-13 18:09:36 +03:00
e296aaa6b3 Update dependency redis to ~=6.1.0
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 1m39s
Tests / Build and Test (3.11) (pull_request) Successful in 1m19s
Tests / Build and Test (3.12) (pull_request) Successful in 1m26s
Tests / Build and Test (3.13) (pull_request) Successful in 1m18s
Analysis / SonarCloud (push) Successful in 49s
2025-05-13 16:06:05 +03:00
6de12244ec Update dependency pylint to v3.3.7
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 45s
Tests / Build and Test (3.11) (pull_request) Successful in 1m9s
Tests / Build and Test (3.12) (pull_request) Successful in 1m8s
Tests / Build and Test (3.13) (pull_request) Successful in 1m9s
Analysis / SonarCloud (push) Successful in 53s
2025-05-04 20:55:27 +03:00
e45266a977 Update dependency redis to v6
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 44s
Tests / Build and Test (3.11) (pull_request) Successful in 1m7s
Tests / Build and Test (3.12) (pull_request) Successful in 1m6s
Tests / Build and Test (3.13) (pull_request) Successful in 1m6s
Analysis / SonarCloud (push) Successful in 48s
2025-04-30 22:28:51 +03:00
9f1179f330 Update dependency redis to ~=5.3.0
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 1m36s
Tests / Build and Test (3.11) (pull_request) Successful in 1m23s
Tests / Build and Test (3.12) (pull_request) Successful in 1m23s
Tests / Build and Test (3.13) (pull_request) Successful in 1m22s
Analysis / SonarCloud (push) Successful in 53s
2025-04-30 18:22:21 +03:00
0690a0fe22 Update dependency pytest-cov to v6.1.1
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 39s
Tests / Build and Test (3.11) (pull_request) Successful in 1m10s
Tests / Build and Test (3.12) (pull_request) Successful in 1m8s
Tests / Build and Test (3.13) (pull_request) Successful in 1m5s
Analysis / SonarCloud (push) Successful in 51s
2025-04-05 17:22:39 +03:00
74f5d638e3 Update dependency pytest-cov to v6.1.0
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 39s
Tests / Build and Test (3.11) (pull_request) Successful in 1m11s
Tests / Build and Test (3.12) (pull_request) Successful in 1m6s
Tests / Build and Test (3.13) (pull_request) Successful in 1m5s
Analysis / SonarCloud (push) Successful in 1m38s
2025-04-01 14:38:36 +03:00
809e103aa3 Merge pull request 'Update dependency tox to v4.25.0' (#198) from renovate/tox-4.x into dev
All checks were successful
Analysis / SonarCloud (push) Successful in 46s
Reviewed-on: #198
2025-03-27 17:57:47 +02:00
6171dac7b8 Update dependency tox to v4.25.0
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 39s
Tests / Build and Test (3.11) (pull_request) Successful in 1m9s
Tests / Build and Test (3.12) (pull_request) Successful in 1m7s
Tests / Build and Test (3.13) (pull_request) Successful in 1m4s
2025-03-27 17:30:45 +02:00
b7f847752c Update dependency types-ujson to v5.10.0.20250326
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 42s
Tests / Build and Test (3.11) (pull_request) Successful in 1m12s
Tests / Build and Test (3.12) (pull_request) Successful in 1m5s
Tests / Build and Test (3.13) (pull_request) Successful in 1m3s
Analysis / SonarCloud (push) Successful in 49s
2025-03-26 07:32:40 +02:00
cb5e6c7bdb Update dependency typing-extensions to ~=4.13.0
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 38s
Tests / Build and Test (3.11) (pull_request) Successful in 1m11s
Tests / Build and Test (3.12) (pull_request) Successful in 1m8s
Tests / Build and Test (3.13) (pull_request) Successful in 1m4s
Analysis / SonarCloud (push) Successful in 49s
2025-03-26 06:30:43 +02:00
762c20a213 Update dependency types-aiofiles to v24.1.0.20250326
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 50s
Tests / Build and Test (3.11) (pull_request) Successful in 1m31s
Tests / Build and Test (3.12) (pull_request) Successful in 1m11s
Tests / Build and Test (3.13) (pull_request) Successful in 1m10s
Analysis / SonarCloud (push) Successful in 46s
2025-03-26 05:28:21 +02:00
e34cb7f4b1 Update dependency pytest-asyncio to v0.26.0
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 47s
Tests / Build and Test (3.11) (pull_request) Successful in 1m14s
Tests / Build and Test (3.12) (pull_request) Successful in 1m10s
Tests / Build and Test (3.13) (pull_request) Successful in 1m5s
Analysis / SonarCloud (push) Successful in 52s
2025-03-25 08:50:28 +02:00
7908d0b906 Update dependency pylint to v3.3.6
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 41s
Tests / Build and Test (3.11) (pull_request) Successful in 1m9s
Tests / Build and Test (3.12) (pull_request) Successful in 1m5s
Tests / Build and Test (3.13) (pull_request) Successful in 1m4s
Analysis / SonarCloud (push) Successful in 43s
2025-03-20 13:40:52 +02:00
cc41f4aa83 Update dependency pylint to v3.3.5
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 38s
Tests / Build and Test (3.11) (pull_request) Successful in 1m8s
Tests / Build and Test (3.12) (pull_request) Successful in 1m6s
Tests / Build and Test (3.13) (pull_request) Successful in 1m3s
Analysis / SonarCloud (push) Successful in 45s
2025-03-09 09:34:58 +02:00
f29a6e4896 Update dependency tox to v4.24.2
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 43s
Tests / Build and Test (3.11) (pull_request) Successful in 1m9s
Tests / Build and Test (3.12) (pull_request) Successful in 1m6s
Tests / Build and Test (3.13) (pull_request) Successful in 1m5s
Analysis / SonarCloud (push) Successful in 51s
2025-03-07 20:38:14 +02:00
2bb62373d6 Merge pull request 'Update dependency pytest to v8.3.5' (#190) from renovate/pytest-8.x into dev
All checks were successful
Analysis / SonarCloud (push) Successful in 46s
Reviewed-on: #190
2025-03-02 16:19:26 +02:00
0ee1c75031 Update dependency pytest to v8.3.5
All checks were successful
Analysis / SonarCloud (pull_request) Successful in 42s
Tests / Build and Test (3.11) (pull_request) Successful in 1m7s
Tests / Build and Test (3.12) (pull_request) Successful in 1m5s
Tests / Build and Test (3.13) (pull_request) Successful in 1m2s
2025-03-02 15:25:02 +02:00
10 changed files with 88 additions and 42 deletions

View File

@@ -16,6 +16,7 @@ There are different sub-packages available:
* pyrogram - Telegram bots with Pyrogram's fork "Pyrofork" * pyrogram - Telegram bots with Pyrogram's fork "Pyrofork"
* pycord - Discord bots with Pycord * pycord - Discord bots with Pycord
* speed - Performance improvements * speed - Performance improvements
* cache - Support for Redis and Memcached
* dev - Dependencies for package development purposes * 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. You can freely choose any sub-package you want, as well as add multiple (comma-separated) or none at all.

View File

@@ -1,5 +1,5 @@
[build-system] [build-system]
requires = ["setuptools>=62.6", "wheel"] requires = ["setuptools>=77.0.3", "wheel"]
build-backend = "setuptools.build_meta" build-backend = "setuptools.build_meta"
[project] [project]
@@ -9,11 +9,11 @@ authors = [{ name = "Profitroll" }]
description = "Universal bot library with functions needed for basic Discord/Telegram bot development." description = "Universal bot library with functions needed for basic Discord/Telegram bot development."
readme = "README.md" readme = "README.md"
requires-python = ">=3.11" requires-python = ">=3.11"
license = { text = "GPLv3" } license = "GPL-3.0"
license-files = ["LICENSE"]
classifiers = [ classifiers = [
"Development Status :: 3 - Alpha", "Development Status :: 3 - Alpha",
"Intended Audience :: Developers", "Intended Audience :: Developers",
"License :: OSI Approved :: GNU General Public License v3 (GPLv3)",
"Operating System :: OS Independent", "Operating System :: OS Independent",
"Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.12",

View File

@@ -1,2 +1,2 @@
aiofiles>=23.0.0 aiofiles>=23.0.0
typing-extensions~=4.12.2 typing-extensions~=4.14.0

View File

@@ -1,2 +1,2 @@
pymemcache~=4.0.0 pymemcache~=4.0.0
redis~=5.2.1 redis~=6.2.0

View File

@@ -1,12 +1,12 @@
black==25.1.0 black==25.1.0
build==1.2.2.post1 build==1.2.2.post1
isort==5.13.2 isort==5.13.2
mypy==1.15.0 mypy==1.16.1
pylint==3.3.4 pylint==3.3.7
pytest-asyncio==0.25.3 pytest-asyncio==1.0.0
pytest-cov==6.0.0 pytest-cov==6.2.1
pytest==8.3.4 pytest==8.4.1
tox==4.24.0 tox==4.27.0
twine==6.1.0 twine==6.1.0
types-aiofiles==24.1.0.20241221 types-aiofiles==24.1.0.20250606
types-ujson==5.10.0.20240515 types-ujson==5.10.0.20250326

View File

@@ -1,4 +1,4 @@
__version__ = "4.1.0" __version__ = "4.3.0"
__license__ = "GPL3" __license__ = "GPL3"
__author__ = "Profitroll" __author__ = "Profitroll"

View File

@@ -1,5 +1,5 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from typing import Any, Dict from typing import Any, Dict, Optional
import pymemcache import pymemcache
import redis import redis
@@ -27,16 +27,16 @@ class Cache(ABC):
pass pass
@abstractmethod @abstractmethod
def set_json(self, key: str, value: Any) -> None: def set_json(self, key: str, value: Any, ttl_seconds: Optional[int] = None) -> None:
# TODO This method must also carry out ObjectId conversion! # TODO This method must also carry out ObjectId conversion!
pass pass
@abstractmethod @abstractmethod
def set_string(self, key: str, value: str) -> None: def set_string(self, key: str, value: str, ttl_seconds: Optional[int] = None) -> None:
pass pass
@abstractmethod @abstractmethod
def set_object(self, key: str, value: Any) -> None: def set_object(self, key: str, value: Any, ttl_seconds: Optional[int] = None) -> None:
pass pass
@abstractmethod @abstractmethod

View File

@@ -1,6 +1,6 @@
import logging import logging
from logging import Logger from logging import Logger
from typing import Dict, Any from typing import Dict, Any, Optional
from pymemcache import Client from pymemcache import Client
@@ -13,21 +13,30 @@ logger: Logger = logging.getLogger(__name__)
class CacheMemcached(Cache): class CacheMemcached(Cache):
client: Client client: Client
def __init__(self, client: Client): def __init__(
self.client = client self, client: Client, prefix: Optional[str] = None, default_ttl_seconds: Optional[int] = None
) -> None:
self.client: Client = client
self.prefix: str | None = prefix
self.default_ttl_seconds: int = default_ttl_seconds if default_ttl_seconds is not None else 0
logger.info("Initialized Memcached for caching") logger.info("Initialized Memcached for caching")
@classmethod @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: if "uri" not in engine_config:
raise KeyError( raise KeyError(
"Cache configuration is invalid. Please check if all keys are set (engine: memcached)" "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: def get_json(self, key: str) -> Any | None:
key = self._get_prefixed_key(key)
try: try:
result: Any | None = self.client.get(key, None) result: Any | None = self.client.get(key, None)
@@ -43,6 +52,8 @@ class CacheMemcached(Cache):
return None if result is None else _string_to_json(result) return None if result is None else _string_to_json(result)
def get_string(self, key: str) -> str | None: def get_string(self, key: str) -> str | None:
key = self._get_prefixed_key(key)
try: try:
result: str | None = self.client.get(key, None) result: str | None = self.client.get(key, None)
@@ -61,27 +72,39 @@ class CacheMemcached(Cache):
def get_object(self, key: str) -> Any | None: def get_object(self, key: str) -> Any | None:
raise NotImplementedError() raise NotImplementedError()
def set_json(self, key: str, value: Any) -> None: def set_json(self, key: str, value: Any, ttl_seconds: Optional[int] = None) -> None:
key = self._get_prefixed_key(key)
try: try:
self.client.set(key, _json_to_string(value)) self.client.set(
key,
_json_to_string(value),
expire=self.default_ttl_seconds if ttl_seconds is None else ttl_seconds,
)
logger.debug("Set json cache key '%s'", key) logger.debug("Set json cache key '%s'", key)
except Exception as exc: except Exception as exc:
logger.error("Could not set json cache key '%s' due to: %s", key, exc) logger.error("Could not set json cache key '%s' due to: %s", key, exc)
return None return None
def set_string(self, key: str, value: str) -> None: def set_string(self, key: str, value: str, ttl_seconds: Optional[int] = None) -> None:
key = self._get_prefixed_key(key)
try: try:
self.client.set(key, value) self.client.set(
key, value, expire=self.default_ttl_seconds if ttl_seconds is None else ttl_seconds
)
logger.debug("Set string cache key '%s'", key) logger.debug("Set string cache key '%s'", key)
except Exception as exc: except Exception as exc:
logger.error("Could not set string cache key '%s' due to: %s", key, exc) logger.error("Could not set string cache key '%s' due to: %s", key, exc)
return None return None
# TODO Implement binary serialization # TODO Implement binary serialization
def set_object(self, key: str, value: Any) -> None: def set_object(self, key: str, value: Any, ttl_seconds: Optional[int] = None) -> None:
raise NotImplementedError() raise NotImplementedError()
def delete(self, key: str) -> None: def delete(self, key: str) -> None:
key = self._get_prefixed_key(key)
try: try:
self.client.delete(key) self.client.delete(key)
logger.debug("Deleted cache key '%s'", key) logger.debug("Deleted cache key '%s'", key)

View File

@@ -1,11 +1,11 @@
import logging import logging
from logging import Logger from logging import Logger
from typing import Dict, Any from typing import Dict, Any, Optional
from redis import Redis from redis import Redis
from .cache import Cache from .cache import Cache
from ..utils._objects import _string_to_json, _json_to_string from ..utils._objects import _json_to_string, _string_to_json
logger: Logger = logging.getLogger(__name__) logger: Logger = logging.getLogger(__name__)
@@ -13,21 +13,30 @@ logger: Logger = logging.getLogger(__name__)
class CacheRedis(Cache): class CacheRedis(Cache):
client: Redis client: Redis
def __init__(self, client: Redis): def __init__(
self.client = client self, client: Redis, prefix: Optional[str] = None, default_ttl_seconds: Optional[int] = None
) -> None:
self.client: Redis = client
self.prefix: str | None = prefix
self.default_ttl_seconds: int | None = default_ttl_seconds
logger.info("Initialized Redis for caching") logger.info("Initialized Redis for caching")
@classmethod @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: if "uri" not in engine_config:
raise KeyError( raise KeyError(
"Cache configuration is invalid. Please check if all keys are set (engine: memcached)" "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: def get_json(self, key: str) -> Any | None:
key = self._get_prefixed_key(key)
try: try:
result: Any | None = self.client.get(key) result: Any | None = self.client.get(key)
@@ -43,6 +52,8 @@ class CacheRedis(Cache):
return None if result is None else _string_to_json(result) return None if result is None else _string_to_json(result)
def get_string(self, key: str) -> str | None: def get_string(self, key: str) -> str | None:
key = self._get_prefixed_key(key)
try: try:
result: str | None = self.client.get(key) result: str | None = self.client.get(key)
@@ -61,27 +72,37 @@ class CacheRedis(Cache):
def get_object(self, key: str) -> Any | None: def get_object(self, key: str) -> Any | None:
raise NotImplementedError() raise NotImplementedError()
def set_json(self, key: str, value: Any) -> None: def set_json(self, key: str, value: Any, ttl_seconds: Optional[int] = None) -> None:
key = self._get_prefixed_key(key)
try: try:
self.client.set(key, _json_to_string(value)) self.client.set(
key,
_json_to_string(value),
ex=self.default_ttl_seconds if ttl_seconds is None else ttl_seconds,
)
logger.debug("Set json cache key '%s'", key) logger.debug("Set json cache key '%s'", key)
except Exception as exc: except Exception as exc:
logger.error("Could not set json cache key '%s' due to: %s", key, exc) logger.error("Could not set json cache key '%s' due to: %s", key, exc)
return None return None
def set_string(self, key: str, value: str) -> None: def set_string(self, key: str, value: str, ttl_seconds: Optional[int] = None) -> None:
key = self._get_prefixed_key(key)
try: try:
self.client.set(key, value) self.client.set(key, value, ex=self.default_ttl_seconds if ttl_seconds is None else ttl_seconds)
logger.debug("Set string cache key '%s'", key) logger.debug("Set string cache key '%s'", key)
except Exception as exc: except Exception as exc:
logger.error("Could not set string cache key '%s' due to: %s", key, exc) logger.error("Could not set string cache key '%s' due to: %s", key, exc)
return None return None
# TODO Implement binary serialization # TODO Implement binary serialization
def set_object(self, key: str, value: Any) -> None: def set_object(self, key: str, value: Any, ttl_seconds: Optional[int] = None) -> None:
raise NotImplementedError() raise NotImplementedError()
def delete(self, key: str) -> None: def delete(self, key: str) -> None:
key = self._get_prefixed_key(key)
try: try:
self.client.delete(key) self.client.delete(key)
logger.debug("Deleted cache key '%s'", key) logger.debug("Deleted cache key '%s'", key)

View File

@@ -1,4 +1,4 @@
from typing import Dict, Any, Literal from typing import Dict, Any, Literal, Optional
from ..classes import CacheMemcached, CacheRedis from ..classes import CacheMemcached, CacheRedis
@@ -6,6 +6,7 @@ from ..classes import CacheMemcached, CacheRedis
def create_cache_client( def create_cache_client(
config: Dict[str, Any], config: Dict[str, Any],
engine: Literal["memcached", "redis"] | None = None, engine: Literal["memcached", "redis"] | None = None,
prefix: Optional[str] = None,
) -> CacheMemcached | CacheRedis: ) -> CacheMemcached | CacheRedis:
if engine not in ["memcached", "redis"] or engine is None: if engine not in ["memcached", "redis"] or engine is None:
raise KeyError(f"Incorrect cache engine provided. Expected 'memcached' or 'redis', got '{engine}'") raise KeyError(f"Incorrect cache engine provided. Expected 'memcached' or 'redis', got '{engine}'")
@@ -17,8 +18,8 @@ def create_cache_client(
match engine: match engine:
case "memcached": case "memcached":
return CacheMemcached.from_config(config["cache"][engine]) return CacheMemcached.from_config(config["cache"][engine], prefix=prefix)
case "redis": case "redis":
return CacheRedis.from_config(config["cache"][engine]) return CacheRedis.from_config(config["cache"][engine], prefix=prefix)
case _: case _:
raise KeyError(f"Cache implementation for the engine '{engine}' is not present.") raise KeyError(f"Cache implementation for the engine '{engine}' is not present.")