diff --git a/discord/guild.py b/discord/guild.py index 9bbed3f737..7a77962812 100644 --- a/discord/guild.py +++ b/discord/guild.py @@ -37,6 +37,7 @@ Optional, Sequence, Tuple, + TypeVar, Union, overload, ) @@ -895,6 +896,64 @@ def get_member(self, user_id: int, /) -> Member | None: """ return self._members.get(user_id) + _FETCHABLE = TypeVar( + "_FETCHABLE", + bound=Union[ + VoiceChannel, + TextChannel, + ForumChannel, + StageChannel, + CategoryChannel, + Thread, + Member, + ], + ) + + async def get_or_fetch( + self, object_type: Type[_FETCHABLE], object_id: int, / + ) -> _FETCHABLE | None: + """Shortcut method to get data from guild object if it's cached or fetch from api if it's not. + + Parameters + ---------- + object_type: :class:`Type[VoiceChannel, TextChannel, ForumChannel, StageChannel, CategoryChannel, Thread, Member]` + Type of object to fetch or get. + + object_id: :class:`int` + ID of object to get. + + Returns + ------- + + Optional[:class:`~Type[VoiceChannel, TextChannel, ForumChannel, StageChannel, CategoryChannel, Thread, Member]`] + The object of type that was specified or ``None`` if not found. + + Usage + ----- + ``await GUILD_OBJECT.get_or_fetch(OBJECT_TYPE, OBJECT_ID)`` + """ + + def get_attr_name(t: object_type) -> str: + if t is Member: + return "member" + elif t in [ + VoiceChannel, + TextChannel, + ForumChannel, + StageChannel, + CategoryChannel, + Thread, + ]: + return "channel" + + raise InvalidArgument( + f"Class {object_type} cannot be used with discord.Guild.get_or_fetch()" + ) + + return await utils.get_or_fetch( + obj=self, attr=get_attr_name(object_type), id=object_id, default=None + ) + @property def premium_subscribers(self) -> list[Member]: """List[:class:`Member`]: A list of members who have "boosted" this guild."""