From 5230ac9ace8addb8fc2040fd9ec11fe02d380207 Mon Sep 17 00:00:00 2001 From: profitroll Date: Tue, 22 Apr 2025 23:22:01 +0200 Subject: [PATCH] Improved caching and utils structure --- classes/pycord_bot.py | 4 ++-- classes/pycord_event.py | 17 +++++++++----- classes/pycord_event_stage.py | 11 +++++----- classes/pycord_guild.py | 9 ++++---- classes/pycord_user.py | 9 ++++---- cogs/config.py | 2 +- cogs/event.py | 2 +- cogs/guess.py | 2 +- main.py | 2 +- modules/__init__.py | 1 + modules/utils/__init__.py | 8 +++++++ .../{utils.py => utils/autocomplete_utils.py} | 22 ++++++++----------- modules/utils/cache_utils.py | 10 +++++++++ modules/utils/color.py | 6 +++++ modules/{ => utils}/logging_utils.py | 0 15 files changed, 65 insertions(+), 40 deletions(-) create mode 100644 modules/__init__.py create mode 100644 modules/utils/__init__.py rename modules/{utils.py => utils/autocomplete_utils.py} (81%) create mode 100644 modules/utils/cache_utils.py create mode 100644 modules/utils/color.py rename modules/{ => utils}/logging_utils.py (100%) diff --git a/classes/pycord_bot.py b/classes/pycord_bot.py index 26137bf..d69104a 100644 --- a/classes/pycord_bot.py +++ b/classes/pycord_bot.py @@ -7,8 +7,8 @@ from libbot.cache.classes import CacheMemcached, CacheRedis from libbot.cache.manager import create_cache_client from libbot.pycord.classes import PycordBot as LibPycordBot -from classes import PycordEvent, PycordGuild, PycordUser, PycordEventStage -from modules.logging_utils import get_logger +from classes import PycordEvent, PycordEventStage, PycordGuild, PycordUser +from modules.utils import get_logger logger: Logger = get_logger(__name__) diff --git a/classes/pycord_event.py b/classes/pycord_event.py index f9962c6..a584df2 100644 --- a/classes/pycord_event.py +++ b/classes/pycord_event.py @@ -10,7 +10,7 @@ from libbot.cache.classes import Cache from pymongo.results import InsertOneResult from modules.database import col_events -from modules.logging_utils import get_logger +from modules.utils import get_logger, restore_from_cache logger: Logger = get_logger(__name__) @@ -59,11 +59,10 @@ class PycordEvent: Raises: EventNotFoundError: Event was not found """ - if cache is not None: - cached_entry: Dict[str, Any] | None = cache.get_json(f"{cls.__short_name__}_{event_id}") + cached_entry: Dict[str, Any] | None = restore_from_cache(cls.__short_name__, event_id, cache=cache) - if cached_entry is not None: - return cls(**cached_entry) + if cached_entry is not None: + return cls(**cached_entry) db_entry = await cls.__collection__.find_one( {"_id": event_id if isinstance(event_id, ObjectId) else ObjectId(event_id)} @@ -326,3 +325,11 @@ class PycordEvent: await self._set(cache, stage_ids=self.stage_ids) await self._update_event_stage_order(bot, old_stage_ids, cache=cache) + + # # TODO Add documentation + # def get_localized_start_date(self, tz: str | timezone | ZoneInfo) -> datetime: + # return self.starts.replace(tzinfo=tz) + # + # # TODO Add documentation + # def get_localized_end_date(self, tz: str | timezone | ZoneInfo) -> datetime: + # return self.ends.replace(tzinfo=tz) diff --git a/classes/pycord_event_stage.py b/classes/pycord_event_stage.py index 5de4cbd..e7a17d7 100644 --- a/classes/pycord_event_stage.py +++ b/classes/pycord_event_stage.py @@ -1,7 +1,7 @@ from dataclasses import dataclass from datetime import datetime from logging import Logger -from typing import List, Dict, Any, Optional +from typing import Any, Dict, List, Optional from zoneinfo import ZoneInfo from bson import ObjectId @@ -9,7 +9,7 @@ from libbot.cache.classes import Cache from pymongo.results import InsertOneResult from modules.database import col_stages -from modules.logging_utils import get_logger +from modules.utils import get_logger, restore_from_cache logger: Logger = get_logger(__name__) @@ -54,11 +54,10 @@ class PycordEventStage: Raises: EventStageNotFoundError: Event stage was not found """ - if cache is not None: - cached_entry: Dict[str, Any] | None = cache.get_json(f"{cls.__short_name__}_{stage_id}") + cached_entry: Dict[str, Any] | None = restore_from_cache(cls.__short_name__, stage_id, cache=cache) - if cached_entry is not None: - return cls(**cached_entry) + if cached_entry is not None: + return cls(**cached_entry) db_entry = await cls.__collection__.find_one( {"_id": stage_id if isinstance(stage_id, ObjectId) else ObjectId(stage_id)} diff --git a/classes/pycord_guild.py b/classes/pycord_guild.py index a56a40f..f61dabe 100644 --- a/classes/pycord_guild.py +++ b/classes/pycord_guild.py @@ -8,7 +8,7 @@ from pymongo.results import InsertOneResult from classes.errors import GuildNotFoundError from modules.database import col_guilds -from modules.logging_utils import get_logger +from modules.utils import get_logger, restore_from_cache logger: Logger = get_logger(__name__) @@ -45,11 +45,10 @@ class PycordGuild: Raises: GuildNotFoundError: User was not found and creation was not allowed """ - if cache is not None: - cached_entry: Dict[str, Any] | None = cache.get_json(f"{cls.__short_name__}_{guild_id}") + cached_entry: Dict[str, Any] | None = restore_from_cache(cls.__short_name__, guild_id, cache=cache) - if cached_entry is not None: - return cls(**cached_entry) + if cached_entry is not None: + return cls(**cached_entry) db_entry = await cls.__collection__.find_one({"id": guild_id}) diff --git a/classes/pycord_user.py b/classes/pycord_user.py index 7ae3b96..16d7458 100644 --- a/classes/pycord_user.py +++ b/classes/pycord_user.py @@ -8,7 +8,7 @@ from pymongo.results import InsertOneResult from classes.errors.pycord_user import UserNotFoundError from modules.database import col_users -from modules.logging_utils import get_logger +from modules.utils import get_logger, restore_from_cache logger: Logger = get_logger(__name__) @@ -41,11 +41,10 @@ class PycordUser: Raises: UserNotFoundError: User was not found and creation was not allowed """ - if cache is not None: - cached_entry: Dict[str, Any] | None = cache.get_json(f"{cls.__short_name__}_{user_id}") + cached_entry: Dict[str, Any] | None = restore_from_cache(cls.__short_name__, user_id, cache=cache) - if cached_entry is not None: - return cls(**cached_entry) + if cached_entry is not None: + return cls(**cached_entry) db_entry = await cls.__collection__.find_one({"id": user_id}) diff --git a/cogs/config.py b/cogs/config.py index 267bc88..9cc8b6a 100644 --- a/cogs/config.py +++ b/cogs/config.py @@ -12,7 +12,7 @@ from discord.utils import basic_autocomplete from classes import PycordGuild from classes.pycord_bot import PycordBot -from modules.utils import autocomplete_timezones, autocomplete_languages +from modules.utils import autocomplete_languages, autocomplete_timezones class Config(Cog): diff --git a/cogs/event.py b/cogs/event.py index 19da64e..36dd577 100644 --- a/cogs/event.py +++ b/cogs/event.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import Dict, Any +from typing import Any, Dict from zoneinfo import ZoneInfo from bson import ObjectId diff --git a/cogs/guess.py b/cogs/guess.py index bc32f52..b8bfffa 100644 --- a/cogs/guess.py +++ b/cogs/guess.py @@ -1,4 +1,4 @@ -from discord import Cog, slash_command, option, ApplicationContext +from discord import ApplicationContext, Cog, option, slash_command from classes.pycord_bot import PycordBot diff --git a/main.py b/main.py index 9ce536d..494f84d 100644 --- a/main.py +++ b/main.py @@ -10,9 +10,9 @@ from discord import LoginFailure from libbot.utils import config_get from classes.pycord_bot import PycordBot -from modules.logging_utils import get_logger, get_logging_config from modules.migrator import migrate_database from modules.scheduler import scheduler +from modules.utils import get_logger, get_logging_config makedirs(Path("logs/"), exist_ok=True) diff --git a/modules/__init__.py b/modules/__init__.py new file mode 100644 index 0000000..e686dad --- /dev/null +++ b/modules/__init__.py @@ -0,0 +1 @@ +from . import utils, database, migrator, scheduler diff --git a/modules/utils/__init__.py b/modules/utils/__init__.py new file mode 100644 index 0000000..0c02512 --- /dev/null +++ b/modules/utils/__init__.py @@ -0,0 +1,8 @@ +from .autocomplete_utils import ( + autocomplete_active_events, + autocomplete_event_stages, + autocomplete_languages, + autocomplete_timezones, +) +from .cache_utils import restore_from_cache +from .logging_utils import get_logger, get_logging_config diff --git a/modules/utils.py b/modules/utils/autocomplete_utils.py similarity index 81% rename from modules/utils.py rename to modules/utils/autocomplete_utils.py index fce03fb..74e751b 100644 --- a/modules/utils.py +++ b/modules/utils/autocomplete_utils.py @@ -1,5 +1,5 @@ from datetime import datetime -from typing import List, Dict, Any +from typing import Any, Dict, List from zoneinfo import ZoneInfo, available_timezones from bson import ObjectId @@ -9,28 +9,23 @@ from pymongo import ASCENDING from modules.database import col_events, col_stages -def hex_to_int(hex_color: str) -> int: - return int(hex_color.lstrip("#"), 16) - - -def int_to_hex(integer_color: int) -> str: - return "#" + format(integer_color, "06x") - - -# TODO Maybe move to a separate module async def autocomplete_timezones(ctx: AutocompleteContext) -> List[str]: + """Return available timezones""" + return sorted(list(available_timezones())) -# TODO Maybe move to a separate module async def autocomplete_languages(ctx: AutocompleteContext) -> List[str]: + """Return locales supported by the bot""" + # TODO Discord normally uses a different set of locales. # For example, "en" being "en-US", etc. This will require changes to locale handling later. return ctx.bot.locales.keys() -# TODO Maybe move to a separate module async def autocomplete_active_events(ctx: AutocompleteContext) -> List[OptionChoice]: + """Return list of active events""" + query: Dict[str, Any] = { "ended": None, "ends": {"$gt": datetime.now(tz=ZoneInfo("UTC"))}, @@ -45,8 +40,9 @@ async def autocomplete_active_events(ctx: AutocompleteContext) -> List[OptionCho return event_names -# TODO Maybe move to a separate module async def autocomplete_event_stages(ctx: AutocompleteContext) -> List[OptionChoice]: + """Return list of stages of the event""" + event_id: str | None = ctx.options["event"] if event_id is None: diff --git a/modules/utils/cache_utils.py b/modules/utils/cache_utils.py new file mode 100644 index 0000000..cec2b14 --- /dev/null +++ b/modules/utils/cache_utils.py @@ -0,0 +1,10 @@ +from typing import Any, Dict, Optional + +from bson import ObjectId +from libbot.cache.classes import Cache + + +def restore_from_cache( + cache_prefix: str, cache_key: str | int | ObjectId, cache: Optional[Cache] = None +) -> Dict[str, Any] | None: + return None if cache is None else cache.get_json(f"{cache_prefix}_{cache_key}") diff --git a/modules/utils/color.py b/modules/utils/color.py new file mode 100644 index 0000000..bc1a6e1 --- /dev/null +++ b/modules/utils/color.py @@ -0,0 +1,6 @@ +def hex_to_int(hex_color: str) -> int: + return int(hex_color.lstrip("#"), 16) + + +def int_to_hex(integer_color: int) -> str: + return "#" + format(integer_color, "06x") diff --git a/modules/logging_utils.py b/modules/utils/logging_utils.py similarity index 100% rename from modules/logging_utils.py rename to modules/utils/logging_utils.py