From 6fdb30176e0eba6c853ee322be73fccbcf6fbf04 Mon Sep 17 00:00:00 2001 From: Tim Paine <3105306+timkpaine@users.noreply.github.com> Date: Mon, 21 Apr 2025 11:13:24 -0400 Subject: [PATCH] Defer backend imports, fixes #1 Signed-off-by: Tim Paine <3105306+timkpaine@users.noreply.github.com> --- csp_bot/__init__.py | 6 +----- csp_bot/backends/__init__.py | 3 +++ csp_bot/backends/discord.py | 23 +++++++++++++++++++++++ csp_bot/backends/slack.py | 24 ++++++++++++++++++++++++ csp_bot/backends/symphony.py | 27 +++++++++++++++++++++++++++ csp_bot/bot.py | 19 +++++++++++++++---- csp_bot/bot_config.py | 5 ++--- csp_bot/structs.py | 4 +--- csp_bot/utils.py | 10 ++++------ pyproject.toml | 7 ++++--- 10 files changed, 104 insertions(+), 24 deletions(-) create mode 100644 csp_bot/backends/__init__.py create mode 100644 csp_bot/backends/discord.py create mode 100644 csp_bot/backends/slack.py create mode 100644 csp_bot/backends/symphony.py diff --git a/csp_bot/__init__.py b/csp_bot/__init__.py index e7657a9..667427f 100644 --- a/csp_bot/__init__.py +++ b/csp_bot/__init__.py @@ -1,11 +1,7 @@ __version__ = "1.0.0" -# reexport -from csp_adapter_discord import DiscordAdapterConfig -from csp_adapter_slack import SlackAdapterConfig -from csp_adapter_symphony import SymphonyAdapterConfig - +from .backends import * from .bot import Bot from .bot_config import * from .commands import * diff --git a/csp_bot/backends/__init__.py b/csp_bot/backends/__init__.py new file mode 100644 index 0000000..b31c868 --- /dev/null +++ b/csp_bot/backends/__init__.py @@ -0,0 +1,3 @@ +from .discord import * +from .slack import * +from .symphony import * diff --git a/csp_bot/backends/discord.py b/csp_bot/backends/discord.py new file mode 100644 index 0000000..ee49b0c --- /dev/null +++ b/csp_bot/backends/discord.py @@ -0,0 +1,23 @@ +from csp import Struct +from pydantic import BaseModel + +__all__ = ( + "DiscordAdapterConfig", + "DiscordAdapterManager", + "DiscordMessage", + "mention_user_discord", +) + +try: + from csp_adapter_discord import DiscordAdapterConfig, DiscordAdapterManager, DiscordMessage, mention_user as mention_user_discord +except ImportError: + + class DiscordAdapterConfig(BaseModel): + pass + + DiscordAdapterManager = None + + class DiscordMessage(Struct): + _ignore: str = "" + + mention_user_discord = lambda x: x # noqa: E731 diff --git a/csp_bot/backends/slack.py b/csp_bot/backends/slack.py new file mode 100644 index 0000000..cd93ccc --- /dev/null +++ b/csp_bot/backends/slack.py @@ -0,0 +1,24 @@ +from csp import Struct +from pydantic import BaseModel + +__all__ = ( + "SlackAdapterConfig", + "SlackAdapterManager", + "SlackMessage", + "mention_user_slack", +) + +# reexport +try: + from csp_adapter_slack import SlackAdapterConfig, SlackAdapterManager, SlackMessage, mention_user as mention_user_slack +except ImportError: + + class SlackAdapterConfig(BaseModel): + pass + + SlackAdapterManager = None + + class SlackMessage(Struct): + _ignore: str = "" + + mention_user_slack = lambda x: x # noqa: E731 diff --git a/csp_bot/backends/symphony.py b/csp_bot/backends/symphony.py new file mode 100644 index 0000000..e47c06e --- /dev/null +++ b/csp_bot/backends/symphony.py @@ -0,0 +1,27 @@ +from csp import Struct +from pydantic import BaseModel + +__all__ = ( + "SymphonyAdapterConfig", + "SymphonyAdapter", + "SymphonyMessage", + "Presence", + "mention_user_symphony", +) + +# reexport +try: + from csp_adapter_symphony import SymphonyAdapter, SymphonyAdapterConfig, SymphonyMessage, mention_user as mention_user_symphony + from csp_adapter_symphony.adapter import Presence +except ImportError: + + class SymphonyAdapterConfig(BaseModel): + pass + + SymphonyAdapter = None + Presence = None + + class SymphonyMessage(Struct): + _ignore: str = "" + + mention_user_symphony = lambda x: x # noqa: E731 diff --git a/csp_bot/bot.py b/csp_bot/bot.py index 9728a48..53ed0d5 100644 --- a/csp_bot/bot.py +++ b/csp_bot/bot.py @@ -12,12 +12,17 @@ from bs4 import BeautifulSoup, Tag from croniter import croniter from csp import Outputs, ts -from csp_adapter_discord import DiscordAdapterManager, DiscordMessage as RawDiscordMessage -from csp_adapter_slack import SlackAdapterManager, SlackMessage as RawSlackMessage -from csp_adapter_symphony import SymphonyAdapter, SymphonyMessage as RawSymphonyMessage -from csp_adapter_symphony.adapter import Presence from pydantic import PrivateAttr +from .backends import ( + DiscordAdapterManager, + DiscordMessage as RawDiscordMessage, + Presence, + SlackAdapterManager, + SlackMessage as RawSlackMessage, + SymphonyAdapter, + SymphonyMessage as RawSymphonyMessage, +) from .bot_config import BotConfig from .commands import ( BaseCommand, @@ -59,12 +64,18 @@ class Bot(GatewayModule): def connect(self, channels: GatewayChannels) -> None: if self.config.discord_config: + if DiscordAdapterManager is None: + raise ImportError("Discord adapter not installed. Please install csp-adapter-discord.") self._configs["discord"] = self.config.discord_config self._adapters["discord"] = DiscordAdapterManager(self.config.discord_config.adapter_config) if self.config.slack_config: + if SlackAdapterManager is None: + raise ImportError("Slack adapter not installed. Please install csp-adapter-slack.") self._configs["slack"] = self.config.slack_config self._adapters["slack"] = SlackAdapterManager(self.config.slack_config.adapter_config) if self.config.symphony_config: + if SymphonyAdapter is None: + raise ImportError("Symphony adapter not installed. Please install csp-adapter-symphony.") self._configs["symphony"] = self.config.symphony_config self._adapters["symphony"] = SymphonyAdapter(self.config.symphony_config.adapter_config) diff --git a/csp_bot/bot_config.py b/csp_bot/bot_config.py index 846e2dd..d24a9fe 100644 --- a/csp_bot/bot_config.py +++ b/csp_bot/bot_config.py @@ -1,11 +1,10 @@ from typing import List, Optional, Union from ccflow import BaseModel -from csp_adapter_discord import DiscordAdapterConfig -from csp_adapter_slack import SlackAdapterConfig -from csp_adapter_symphony import SymphonyAdapterConfig from pydantic import Field +from .backends import DiscordAdapterConfig, SlackAdapterConfig, SymphonyAdapterConfig + __all__ = ( "BaseConfig", "BotConfig", diff --git a/csp_bot/structs.py b/csp_bot/structs.py index 21041a5..ba4ed5b 100644 --- a/csp_bot/structs.py +++ b/csp_bot/structs.py @@ -3,11 +3,9 @@ from typing import Tuple, Union from csp import Struct -from csp_adapter_discord import DiscordMessage as BaseDiscordMessage -from csp_adapter_slack import SlackMessage as BaseSlackMessage -from csp_adapter_symphony import SymphonyMessage as BaseSymphonyMessage from csp_gateway.utils.struct import GatewayStruct +from .backends import DiscordMessage as BaseDiscordMessage, SlackMessage as BaseSlackMessage, SymphonyMessage as BaseSymphonyMessage from .utils import Backend __all__ = ( diff --git a/csp_bot/utils.py b/csp_bot/utils.py index 9ffd7d6..77b2278 100644 --- a/csp_bot/utils.py +++ b/csp_bot/utils.py @@ -1,9 +1,7 @@ from typing import Literal from urllib.parse import urlparse # quote -from csp_adapter_discord import mention_user as discord_mention_user -from csp_adapter_slack import mention_user as slack_mention_user -from csp_adapter_symphony import mention_user as symphony_mention_user +from .backends import mention_user_discord, mention_user_slack, mention_user_symphony __all__ = ( "is_valid_url", @@ -58,12 +56,12 @@ def recursive_format_for_message_ml(d): def mention_user(email_or_userid: str = "", backend: Backend = "symphony") -> str: if backend == "symphony": - return symphony_mention_user(email_or_userid) + return mention_user_symphony(email_or_userid) elif backend == "slack": if not email_or_userid.startswith("@"): email_or_userid = f"@{email_or_userid}" - return slack_mention_user(email_or_userid) + return mention_user_slack(email_or_userid) elif backend == "discord": - return discord_mention_user(email_or_userid) + return mention_user_discord(email_or_userid) else: raise NotImplementedError(f"Unsupported backend: {backend}") diff --git a/pyproject.toml b/pyproject.toml index bf76177..1f4fc28 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,9 +38,6 @@ dependencies = [ "croniter", "csp>=0.9,<1", "csp-gateway>=2,<3", - "csp-adapter-discord>=0.1,<0.2", - "csp-adapter-slack>=0.3,<0.4", - "csp-adapter-symphony>=0.3,<0.4", "dateparser", "hydra-core", "pandas", @@ -53,6 +50,9 @@ develop = [ "bump-my-version", "check-manifest", "codespell>=2.2.6,<2.5", + "csp-adapter-discord>=0.1,<0.2", + "csp-adapter-slack>=0.3,<0.4", + "csp-adapter-symphony>=0.3,<0.4", "hatchling", "mdformat>=0.7.17,<0.8", "mdformat-tables>=1,<1.1", @@ -141,4 +141,5 @@ known-first-party = ["csp_bot"] section-order = ["future", "standard-library", "third-party", "first-party", "local-folder"] [tool.ruff.lint.per-file-ignores] +"csp_bot/backends" = ["F401", "F403"] "__init__.py" = ["F401", "F403"]