Skip to content

Commit 440416b

Browse files
authored
fix(channel): improve handling of placeholder guilds in GuildChannel and Thread (#1287)
1 parent a10935a commit 440416b

File tree

4 files changed

+60
-2
lines changed

4 files changed

+60
-2
lines changed

changelog/1287.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Improve checks for partial :class:`Guild`\s in guild-dependent attributes of channels and threads, which could previously raise errors with user-installed apps, as they don't always receive complete guild data.

disnake/abc.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,8 @@ def category(self) -> Optional[CategoryChannel]:
600600
601601
If there is no category then this is ``None``.
602602
"""
603+
if isinstance(self.guild, Object):
604+
return None
603605
return self.guild.get_channel(self.category_id) # type: ignore
604606

605607
@property
@@ -611,7 +613,7 @@ def permissions_synced(self) -> bool:
611613
612614
.. versionadded:: 1.3
613615
"""
614-
if self.category_id is None:
616+
if self.category_id is None or isinstance(self.guild, Object):
615617
return False
616618

617619
category = self.guild.get_channel(self.category_id)
@@ -679,6 +681,13 @@ def permissions_for(
679681
- The default role permission overwrites
680682
- The permission overwrites of the role used as a parameter
681683
684+
.. note::
685+
If the channel originated from an :class:`.Interaction` and
686+
the :attr:`.guild` attribute is unavailable, such as with
687+
user-installed applications in guilds, this method will not work
688+
due to an API limitation.
689+
Consider using :attr:`.Interaction.permissions` or :attr:`~.Interaction.app_permissions` instead.
690+
682691
.. versionchanged:: 2.0
683692
The object passed in can now be a role object.
684693

disnake/channel.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
from .flags import ChannelFlags, MessageFlags
4545
from .iterators import ArchivedThreadIterator
4646
from .mixins import Hashable
47+
from .object import Object
4748
from .partial_emoji import PartialEmoji
4849
from .permissions import PermissionOverwrite, Permissions
4950
from .soundboard import GuildSoundboardSound, PartialSoundboardSound, SoundboardSound
@@ -341,6 +342,8 @@ def permissions_for(
341342
@property
342343
def members(self) -> List[Member]:
343344
"""List[:class:`Member`]: Returns all members that can see this channel."""
345+
if isinstance(self.guild, Object):
346+
return []
344347
return [m for m in self.guild.members if self.permissions_for(m).view_channel]
345348

346349
@property
@@ -349,6 +352,8 @@ def threads(self) -> List[Thread]:
349352
350353
.. versionadded:: 2.0
351354
"""
355+
if isinstance(self.guild, Object):
356+
return []
352357
return [thread for thread in self.guild._threads.values() if thread.parent_id == self.id]
353358

354359
def is_nsfw(self) -> bool:
@@ -978,6 +983,8 @@ def get_thread(self, thread_id: int, /) -> Optional[Thread]:
978983
Optional[:class:`Thread`]
979984
The returned thread or ``None`` if not found.
980985
"""
986+
if isinstance(self.guild, Object):
987+
return None
981988
return self.guild.get_thread(thread_id)
982989

983990
@overload
@@ -1217,6 +1224,9 @@ def _sorting_bucket(self) -> int:
12171224
@property
12181225
def members(self) -> List[Member]:
12191226
"""List[:class:`Member`]: Returns all members that are currently inside this voice channel."""
1227+
if isinstance(self.guild, Object):
1228+
return []
1229+
12201230
ret = []
12211231
for user_id, state in self.guild._voice_states.items():
12221232
if state.channel and state.channel.id == self.id:
@@ -1241,6 +1251,9 @@ def voice_states(self) -> Dict[int, VoiceState]:
12411251
Mapping[:class:`int`, :class:`VoiceState`]
12421252
The mapping of member ID to a voice state.
12431253
"""
1254+
if isinstance(self.guild, Object):
1255+
return {}
1256+
12441257
return {
12451258
key: value
12461259
for key, value in self.guild._voice_states.items()
@@ -2277,6 +2290,8 @@ def instance(self) -> Optional[StageInstance]:
22772290
22782291
.. versionadded:: 2.0
22792292
"""
2293+
if isinstance(self.guild, Object):
2294+
return None
22802295
return utils.get(self.guild.stage_instances, channel_id=self.id)
22812296

22822297
async def create_instance(
@@ -3090,6 +3105,8 @@ def channels(self) -> List[GuildChannelType]:
30903105
30913106
These are sorted by the official Discord UI, which places voice channels below the text channels.
30923107
"""
3108+
if isinstance(self.guild, Object):
3109+
return []
30933110

30943111
def comparator(channel):
30953112
return (
@@ -3104,6 +3121,9 @@ def comparator(channel):
31043121
@property
31053122
def text_channels(self) -> List[TextChannel]:
31063123
"""List[:class:`TextChannel`]: Returns the text channels that are under this category."""
3124+
if isinstance(self.guild, Object):
3125+
return []
3126+
31073127
ret = [
31083128
c
31093129
for c in self.guild.channels
@@ -3115,6 +3135,9 @@ def text_channels(self) -> List[TextChannel]:
31153135
@property
31163136
def voice_channels(self) -> List[VoiceChannel]:
31173137
"""List[:class:`VoiceChannel`]: Returns the voice channels that are under this category."""
3138+
if isinstance(self.guild, Object):
3139+
return []
3140+
31183141
ret = [
31193142
c
31203143
for c in self.guild.channels
@@ -3129,6 +3152,9 @@ def stage_channels(self) -> List[StageChannel]:
31293152
31303153
.. versionadded:: 1.7
31313154
"""
3155+
if isinstance(self.guild, Object):
3156+
return []
3157+
31323158
ret = [
31333159
c
31343160
for c in self.guild.channels
@@ -3143,6 +3169,9 @@ def forum_channels(self) -> List[ForumChannel]:
31433169
31443170
.. versionadded:: 2.5
31453171
"""
3172+
if isinstance(self.guild, Object):
3173+
return []
3174+
31463175
ret = [
31473176
c
31483177
for c in self.guild.channels
@@ -3157,6 +3186,9 @@ def media_channels(self) -> List[MediaChannel]:
31573186
31583187
.. versionadded:: 2.10
31593188
"""
3189+
if isinstance(self.guild, Object):
3190+
return []
3191+
31603192
ret = [
31613193
c
31623194
for c in self.guild.channels
@@ -3368,11 +3400,15 @@ def permissions_for(
33683400
@property
33693401
def members(self) -> List[Member]:
33703402
"""List[:class:`Member`]: Returns all members that can see this channel."""
3403+
if isinstance(self.guild, Object):
3404+
return []
33713405
return [m for m in self.guild.members if self.permissions_for(m).view_channel]
33723406

33733407
@property
33743408
def threads(self) -> List[Thread]:
33753409
"""List[:class:`Thread`]: Returns all the threads that you can see."""
3410+
if isinstance(self.guild, Object):
3411+
return []
33763412
return [thread for thread in self.guild._threads.values() if thread.parent_id == self.id]
33773413

33783414
def is_nsfw(self) -> bool:
@@ -3466,6 +3502,8 @@ def get_thread(self, thread_id: int, /) -> Optional[Thread]:
34663502
Optional[:class:`Thread`]
34673503
The returned thread of ``None`` if not found.
34683504
"""
3505+
if isinstance(self.guild, Object):
3506+
return None
34693507
return self.guild.get_thread(thread_id)
34703508

34713509
@overload

disnake/threads.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from .errors import ClientException
1212
from .flags import ChannelFlags
1313
from .mixins import Hashable
14+
from .object import Object
1415
from .partial_emoji import PartialEmoji, _EmojiTag
1516
from .permissions import Permissions
1617
from .utils import MISSING, _get_as_snowflake, _unique, parse_time, snowflake_time
@@ -244,12 +245,14 @@ def type(self) -> ThreadType:
244245
@property
245246
def parent(self) -> Optional[Union[TextChannel, ForumChannel, MediaChannel]]:
246247
"""Optional[Union[:class:`TextChannel`, :class:`ForumChannel`, :class:`MediaChannel`]]: The parent channel this thread belongs to."""
248+
if isinstance(self.guild, Object):
249+
return None
247250
return self.guild.get_channel(self.parent_id) # type: ignore
248251

249252
@property
250253
def owner(self) -> Optional[Member]:
251254
"""Optional[:class:`Member`]: The member this thread belongs to."""
252-
if self.owner_id is None:
255+
if self.owner_id is None or isinstance(self.guild, Object):
253256
return None
254257
return self.guild.get_member(self.owner_id)
255258

@@ -429,6 +432,13 @@ def permissions_for(
429432
:attr:`GuildChannel.permissions_for <.abc.GuildChannel.permissions_for>`
430433
method directly.
431434
435+
.. note::
436+
If the thread originated from an :class:`.Interaction` and
437+
the :attr:`.guild` attribute is unavailable, such as with
438+
user-installed applications in guilds, this method will not work
439+
due to an API limitation.
440+
Consider using :attr:`.Interaction.permissions` or :attr:`~.Interaction.app_permissions` instead.
441+
432442
.. versionchanged:: 2.9
433443
Properly takes :attr:`Permissions.send_messages_in_threads`
434444
into consideration.

0 commit comments

Comments
 (0)