Skip to content

Commit 9781a6f

Browse files
committed
fix(channel): improve handling of placeholder guilds in GuildChannel and Thread (#1287)
1 parent e6c8100 commit 9781a6f

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
@@ -601,6 +601,8 @@ def category(self) -> Optional[CategoryChannel]:
601601
602602
If there is no category then this is ``None``.
603603
"""
604+
if isinstance(self.guild, Object):
605+
return None
604606
return self.guild.get_channel(self.category_id) # type: ignore
605607

606608
@property
@@ -612,7 +614,7 @@ def permissions_synced(self) -> bool:
612614
613615
.. versionadded:: 1.3
614616
"""
615-
if self.category_id is None:
617+
if self.category_id is None or isinstance(self.guild, Object):
616618
return False
617619

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

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:
@@ -981,6 +986,8 @@ def get_thread(self, thread_id: int, /) -> Optional[Thread]:
981986
Optional[:class:`Thread`]
982987
The returned thread or ``None`` if not found.
983988
"""
989+
if isinstance(self.guild, Object):
990+
return None
984991
return self.guild.get_thread(thread_id)
985992

986993
@overload
@@ -1222,6 +1229,9 @@ def _sorting_bucket(self) -> int:
12221229
@property
12231230
def members(self) -> List[Member]:
12241231
"""List[:class:`Member`]: Returns all members that are currently inside this voice channel."""
1232+
if isinstance(self.guild, Object):
1233+
return []
1234+
12251235
ret = []
12261236
for user_id, state in self.guild._voice_states.items():
12271237
if state.channel and state.channel.id == self.id:
@@ -1246,6 +1256,9 @@ def voice_states(self) -> Dict[int, VoiceState]:
12461256
Mapping[:class:`int`, :class:`VoiceState`]
12471257
The mapping of member ID to a voice state.
12481258
"""
1259+
if isinstance(self.guild, Object):
1260+
return {}
1261+
12491262
return {
12501263
key: value
12511264
for key, value in self.guild._voice_states.items()
@@ -2285,6 +2298,8 @@ def instance(self) -> Optional[StageInstance]:
22852298
22862299
.. versionadded:: 2.0
22872300
"""
2301+
if isinstance(self.guild, Object):
2302+
return None
22882303
return utils.get(self.guild.stage_instances, channel_id=self.id)
22892304

22902305
async def create_instance(
@@ -3107,6 +3122,8 @@ def channels(self) -> List[GuildChannelType]:
31073122
31083123
These are sorted by the official Discord UI, which places voice channels below the text channels.
31093124
"""
3125+
if isinstance(self.guild, Object):
3126+
return []
31103127

31113128
def comparator(channel):
31123129
return (
@@ -3121,6 +3138,9 @@ def comparator(channel):
31213138
@property
31223139
def text_channels(self) -> List[TextChannel]:
31233140
"""List[:class:`TextChannel`]: Returns the text channels that are under this category."""
3141+
if isinstance(self.guild, Object):
3142+
return []
3143+
31243144
ret = [
31253145
c
31263146
for c in self.guild.channels
@@ -3132,6 +3152,9 @@ def text_channels(self) -> List[TextChannel]:
31323152
@property
31333153
def voice_channels(self) -> List[VoiceChannel]:
31343154
"""List[:class:`VoiceChannel`]: Returns the voice channels that are under this category."""
3155+
if isinstance(self.guild, Object):
3156+
return []
3157+
31353158
ret = [
31363159
c
31373160
for c in self.guild.channels
@@ -3146,6 +3169,9 @@ def stage_channels(self) -> List[StageChannel]:
31463169
31473170
.. versionadded:: 1.7
31483171
"""
3172+
if isinstance(self.guild, Object):
3173+
return []
3174+
31493175
ret = [
31503176
c
31513177
for c in self.guild.channels
@@ -3160,6 +3186,9 @@ def forum_channels(self) -> List[ForumChannel]:
31603186
31613187
.. versionadded:: 2.5
31623188
"""
3189+
if isinstance(self.guild, Object):
3190+
return []
3191+
31633192
ret = [
31643193
c
31653194
for c in self.guild.channels
@@ -3174,6 +3203,9 @@ def media_channels(self) -> List[MediaChannel]:
31743203
31753204
.. versionadded:: 2.10
31763205
"""
3206+
if isinstance(self.guild, Object):
3207+
return []
3208+
31773209
ret = [
31783210
c
31793211
for c in self.guild.channels
@@ -3385,11 +3417,15 @@ def permissions_for(
33853417
@property
33863418
def members(self) -> List[Member]:
33873419
"""List[:class:`Member`]: Returns all members that can see this channel."""
3420+
if isinstance(self.guild, Object):
3421+
return []
33883422
return [m for m in self.guild.members if self.permissions_for(m).view_channel]
33893423

33903424
@property
33913425
def threads(self) -> List[Thread]:
33923426
"""List[:class:`Thread`]: Returns all the threads that you can see."""
3427+
if isinstance(self.guild, Object):
3428+
return []
33933429
return [thread for thread in self.guild._threads.values() if thread.parent_id == self.id]
33943430

33953431
def is_nsfw(self) -> bool:
@@ -3483,6 +3519,8 @@ def get_thread(self, thread_id: int, /) -> Optional[Thread]:
34833519
Optional[:class:`Thread`]
34843520
The returned thread of ``None`` if not found.
34853521
"""
3522+
if isinstance(self.guild, Object):
3523+
return None
34863524
return self.guild.get_thread(thread_id)
34873525

34883526
@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)