Skip to content

Commit 0ff1f62

Browse files
feat!: use the guild data provided on interactions
This could in theory use an optimisation of caching the guild, but as we do not have a good way to clear the cache afterwards, this is the best we can implement at this point in time.
1 parent 4aba1f4 commit 0ff1f62

File tree

5 files changed

+67
-11
lines changed

5 files changed

+67
-11
lines changed

changelog/1235.breaking.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:attr:`Interaction.guild` is now a :class:`Guild` instance if the guild could not be found in cache.

disnake/guild.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@
9696
from .app_commands import APIApplicationCommand
9797
from .asset import AssetBytes
9898
from .automod import AutoModTriggerMetadata
99+
from .interactions import Interaction
99100
from .permissions import Permissions
100101
from .state import ConnectionState
101102
from .template import Template
@@ -111,6 +112,7 @@
111112
Guild as GuildPayload,
112113
GuildFeature,
113114
MFALevel,
115+
PartialGuild as PartialGuildPayload,
114116
)
115117
from .types.integration import Integration as IntegrationPayload, IntegrationType
116118
from .types.role import CreateRole as CreateRolePayload
@@ -5211,6 +5213,33 @@ async def fetch_soundboard_sounds(self) -> List[GuildSoundboardSound]:
52115213
]
52125214

52135215

5216+
class PartialInteractionGuild(Guild):
5217+
"""Reimplementation of :class:`Guild` for guilds interactions."""
5218+
5219+
def __init__(
5220+
self,
5221+
*,
5222+
state: ConnectionState,
5223+
data: PartialGuildPayload,
5224+
interaction: Interaction,
5225+
) -> None:
5226+
super().__init__(state=state, data=data)
5227+
# init the fake data
5228+
self._add_role(
5229+
Role(
5230+
state=state,
5231+
guild=self,
5232+
data={"id": self.id, "name": "@everyone"}, # type: ignore
5233+
)
5234+
)
5235+
self._add_channel(interaction.channel) # type: ignore
5236+
# honestly we cannot set me, because we do not necessarily have a user in the guild
5237+
5238+
@property
5239+
def me(self) -> Any:
5240+
return self._state.user
5241+
5242+
52145243
PlaceholderID = NewType("PlaceholderID", int)
52155244

52165245

disnake/interactions/base.py

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
NotFound,
4444
)
4545
from ..flags import InteractionContextTypes, MessageFlags
46-
from ..guild import Guild
46+
from ..guild import Guild, PartialInteractionGuild
4747
from ..http import HTTPClient
4848
from ..i18n import Localized
4949
from ..member import Member
@@ -80,6 +80,7 @@
8080
Modal as ModalPayload,
8181
ModalTopLevelComponent as ModalTopLevelComponentPayload,
8282
)
83+
from ..types.guild import PartialGuild as PartialGuildPayload
8384
from ..types.interactions import (
8485
ApplicationCommandOptionChoice as ApplicationCommandOptionChoicePayload,
8586
Interaction as InteractionPayload,
@@ -222,6 +223,7 @@ class Interaction(Generic[ClientT]):
222223
"_state",
223224
"_session",
224225
"_original_response",
226+
"_guild",
225227
"_cs_response",
226228
"_cs_followup",
227229
"_cs_me",
@@ -242,6 +244,7 @@ def __init__(self, *, data: InteractionPayload, state: ConnectionState) -> None:
242244
self.version: int = data["version"]
243245
self.application_id: int = int(data["application_id"])
244246
self.guild_id: Optional[int] = utils._get_as_snowflake(data, "guild_id")
247+
self._guild: Optional[PartialGuildPayload] = data.get("guild")
245248

246249
self.locale: Locale = try_enum(Locale, data["locale"])
247250
guild_locale = data.get("guild_locale")
@@ -254,19 +257,15 @@ def __init__(self, *, data: InteractionPayload, state: ConnectionState) -> None:
254257
# one of user and member will always exist
255258
self.author: Union[User, Member] = MISSING
256259

257-
guild_fallback: Optional[Union[Guild, Object]] = None
258-
if self.guild_id:
259-
guild_fallback = self.guild or Object(self.guild_id)
260+
guild_fallback: Optional[Guild] = None
260261

261-
if guild_fallback and (member := data.get("member")):
262-
self.author = (
263-
isinstance(guild_fallback, Guild)
264-
and guild_fallback.get_member(int(member["user"]["id"]))
265-
) or Member(
262+
if self.guild_id and (guild_fallback := self.guild) and (member := data.get("member")):
263+
self.author = guild_fallback.get_member(int(member["user"]["id"])) or Member(
266264
state=self._state,
267-
guild=guild_fallback, # type: ignore # may be `Object`
265+
guild=guild_fallback,
268266
data=member,
269267
)
268+
270269
self._permissions = int(member.get("permissions", 0))
271270
elif user := data.get("user"):
272271
self.author = self._state.store_user(user)
@@ -322,8 +321,29 @@ def guild(self) -> Optional[Guild]:
322321
323322
To check whether an interaction was sent from a guild, consider using
324323
:attr:`guild_id` or :attr:`context` instead.
324+
325+
.. versionchanged:: 2.12
326+
Returns a :class:`Guild` object when the guild could not be resolved from cache.
327+
This object is created from the data provided by Discord, but it is not complete.
328+
The only populated attributes are:
329+
- :attr:`Guild.id`
330+
- :attr:`Guild.preferred_locale`
331+
- :attr:`Guild.features`
325332
"""
326-
return self._state._get_guild(self.guild_id)
333+
if self.guild_id is None:
334+
return None
335+
336+
guild = self._state._get_guild(self.guild_id)
337+
if guild:
338+
return guild
339+
if self._guild is None:
340+
return None
341+
342+
# create a guild mash
343+
# honestly we should cache this for the duration of the interaction
344+
# but not if we fetch it from the cache, just the result of this creation
345+
guild = PartialInteractionGuild(data=self._guild, state=self._state, interaction=self)
346+
return guild
327347

328348
@utils.cached_slot_property("_cs_me")
329349
def me(self) -> Union[Member, ClientUser]:

disnake/types/guild.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ class Guild(_BaseGuildPreview):
153153
soundboard_sounds: NotRequired[List[GuildSoundboardSound]]
154154

155155

156+
class PartialGuild(Guild, total=False):
157+
pass
158+
159+
156160
class InviteGuild(Guild, total=False):
157161
welcome_screen: WelcomeScreen
158162

disnake/types/interactions.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
from .components import MessageTopLevelComponent, Modal
1010
from .embed import Embed
1111
from .entitlement import Entitlement
12+
from .guild import PartialGuild
1213
from .i18n import LocalizationDict
1314
from .member import Member, MemberWithUser
1415
from .role import Role
@@ -326,6 +327,7 @@ class _BaseUserInteraction(_BaseInteraction):
326327
channel: InteractionChannel
327328
locale: str
328329
guild_id: NotRequired[Snowflake]
330+
guild: NotRequired[PartialGuild]
329331
guild_locale: NotRequired[str]
330332
entitlements: NotRequired[List[Entitlement]]
331333
authorizing_integration_owners: NotRequired[AuthorizingIntegrationOwners]

0 commit comments

Comments
 (0)