mirror of
https://github.com/Rapptz/discord.py.git
synced 2025-06-03 18:42:43 +00:00
Improve generic duck type programming with PartialMessageable
This adds jump_url, permissions_for, and created_at. Luckily, most cases of this type being constructed already have the guild_id at creation time.
This commit is contained in:
parent
e9c7c09ebf
commit
8699d2139a
@ -213,9 +213,11 @@ class Namespace:
|
||||
for (message_id, message_data) in resolved.get('messages', {}).items():
|
||||
channel_id = int(message_data['channel_id'])
|
||||
if guild is None:
|
||||
channel = PartialMessageable(state=state, id=channel_id)
|
||||
channel = PartialMessageable(state=state, guild_id=guild_id, id=channel_id)
|
||||
else:
|
||||
channel = guild.get_channel_or_thread(channel_id) or PartialMessageable(state=state, id=channel_id)
|
||||
channel = guild.get_channel_or_thread(channel_id) or PartialMessageable(
|
||||
state=state, guild_id=guild_id, id=channel_id
|
||||
)
|
||||
|
||||
# Type checker doesn't understand this due to failure to narrow
|
||||
message = Message(state=state, channel=channel, data=message_data) # type: ignore
|
||||
|
@ -2611,13 +2611,16 @@ class PartialMessageable(discord.abc.Messageable, Hashable):
|
||||
-----------
|
||||
id: :class:`int`
|
||||
The channel ID associated with this partial messageable.
|
||||
guild_id: Optional[:class:`int`]
|
||||
The guild ID associated with this partial messageable.
|
||||
type: Optional[:class:`ChannelType`]
|
||||
The channel type associated with this partial messageable, if given.
|
||||
"""
|
||||
|
||||
def __init__(self, state: ConnectionState, id: int, type: Optional[ChannelType] = None):
|
||||
def __init__(self, state: ConnectionState, id: int, guild_id: Optional[int] = None, type: Optional[ChannelType] = None):
|
||||
self._state: ConnectionState = state
|
||||
self.id: int = id
|
||||
self.guild_id: Optional[int] = guild_id
|
||||
self.type: Optional[ChannelType] = type
|
||||
|
||||
def __repr__(self) -> str:
|
||||
@ -2626,6 +2629,40 @@ class PartialMessageable(discord.abc.Messageable, Hashable):
|
||||
async def _get_channel(self) -> PartialMessageable:
|
||||
return self
|
||||
|
||||
@property
|
||||
def jump_url(self) -> str:
|
||||
""":class:`str`: Returns a URL that allows the client to jump to the channel."""
|
||||
if self.guild_id is None:
|
||||
return f'https://discord.com/channels/@me/{self.id}'
|
||||
return f'https://discord.com/channels/{self.guild_id}/{self.id}'
|
||||
|
||||
@property
|
||||
def created_at(self) -> datetime.datetime:
|
||||
""":class:`datetime.datetime`: Returns the direct message channel's creation time in UTC."""
|
||||
return utils.snowflake_time(self.id)
|
||||
|
||||
def permissions_for(self, obj: Any = None, /) -> Permissions:
|
||||
"""Handles permission resolution for a :class:`User`.
|
||||
|
||||
This function is there for compatibility with other channel types.
|
||||
|
||||
Since partial messageables cannot reasonably have the concept of
|
||||
permissions, this will always return :meth:`Permissions.none`.
|
||||
|
||||
Parameters
|
||||
-----------
|
||||
obj: :class:`User`
|
||||
The user to check permissions for. This parameter is ignored
|
||||
but kept for compatibility with other ``permissions_for`` methods.
|
||||
|
||||
Returns
|
||||
--------
|
||||
:class:`Permissions`
|
||||
The resolved permissions.
|
||||
"""
|
||||
|
||||
return Permissions.none()
|
||||
|
||||
def get_partial_message(self, message_id: int, /) -> PartialMessage:
|
||||
"""Creates a :class:`PartialMessage` from the message ID.
|
||||
|
||||
|
@ -807,7 +807,9 @@ class Client:
|
||||
"""
|
||||
return self._connection.get_channel(id) # type: ignore # The cache contains all channel types
|
||||
|
||||
def get_partial_messageable(self, id: int, *, type: Optional[ChannelType] = None) -> PartialMessageable:
|
||||
def get_partial_messageable(
|
||||
self, id: int, *, guild_id: Optional[int] = None, type: Optional[ChannelType] = None
|
||||
) -> PartialMessageable:
|
||||
"""Returns a partial messageable with the given channel ID.
|
||||
|
||||
This is useful if you have a channel_id but don't want to do an API call
|
||||
@ -819,6 +821,11 @@ class Client:
|
||||
-----------
|
||||
id: :class:`int`
|
||||
The channel ID to create a partial messageable for.
|
||||
guild_id: Optional[:class:`int`]
|
||||
The optional guild ID to create a partial messageable for.
|
||||
|
||||
This is not required to actually send messages, but it does allow the
|
||||
:meth:`PartialMessageable.jump_url` property to form a well formed URL.
|
||||
type: Optional[:class:`.ChannelType`]
|
||||
The underlying channel type for the partial messageable.
|
||||
|
||||
@ -827,7 +834,7 @@ class Client:
|
||||
:class:`.PartialMessageable`
|
||||
The partial messageable
|
||||
"""
|
||||
return PartialMessageable(state=self._connection, id=id, type=type)
|
||||
return PartialMessageable(state=self._connection, id=id, guild_id=guild_id, type=type)
|
||||
|
||||
def get_stage_instance(self, id: int, /) -> Optional[StageInstance]:
|
||||
"""Returns a stage instance with the given stage channel ID.
|
||||
|
@ -244,7 +244,9 @@ class Context(discord.abc.Messageable, Generic[BotT]):
|
||||
if interaction.channel_id is None:
|
||||
raise RuntimeError('interaction channel ID is null, this is probably a Discord bug')
|
||||
|
||||
channel = interaction.channel or PartialMessageable(state=interaction._state, id=interaction.channel_id)
|
||||
channel = interaction.channel or PartialMessageable(
|
||||
state=interaction._state, guild_id=interaction.guild_id, id=interaction.channel_id
|
||||
)
|
||||
message = Message(state=interaction._state, channel=channel, data=synthetic_payload) # type: ignore
|
||||
message.author = interaction.user
|
||||
message.attachments = [a for _, a in interaction.namespace if isinstance(a, Attachment)]
|
||||
|
@ -223,7 +223,7 @@ class Interaction:
|
||||
if channel is None:
|
||||
if self.channel_id is not None:
|
||||
type = ChannelType.text if self.guild_id is not None else ChannelType.private
|
||||
return PartialMessageable(state=self._state, id=self.channel_id, type=type)
|
||||
return PartialMessageable(state=self._state, guild_id=self.guild_id, id=self.channel_id, type=type)
|
||||
return None
|
||||
return channel
|
||||
|
||||
|
@ -480,7 +480,7 @@ class ConnectionState:
|
||||
else:
|
||||
channel = guild and guild._resolve_channel(channel_id)
|
||||
|
||||
return channel or PartialMessageable(state=self, id=channel_id), guild
|
||||
return channel or PartialMessageable(state=self, guild_id=guild_id, id=channel_id), guild
|
||||
|
||||
async def chunker(
|
||||
self, guild_id: int, query: str = '', limit: int = 0, presences: bool = False, *, nonce: Optional[str] = None
|
||||
|
@ -1345,14 +1345,14 @@ class Webhook(BaseWebhook):
|
||||
state = _WebhookState(self, parent=self._state, thread=thread)
|
||||
# state may be artificial (unlikely at this point...)
|
||||
if thread is MISSING:
|
||||
channel = self.channel or PartialMessageable(state=self._state, id=int(data['channel_id'])) # type: ignore
|
||||
channel = self.channel or PartialMessageable(state=self._state, guild_id=self.guild_id, id=int(data['channel_id'])) # type: ignore
|
||||
else:
|
||||
channel = self.channel
|
||||
if isinstance(channel, TextChannel):
|
||||
channel = channel.get_thread(thread.id)
|
||||
|
||||
if channel is None:
|
||||
channel = PartialMessageable(state=self._state, id=int(data['channel_id'])) # type: ignore
|
||||
channel = PartialMessageable(state=self._state, guild_id=self.guild_id, id=int(data['channel_id'])) # type: ignore
|
||||
|
||||
# state is artificial
|
||||
return WebhookMessage(data=data, state=state, channel=channel) # type: ignore
|
||||
|
@ -842,7 +842,7 @@ class SyncWebhook(BaseWebhook):
|
||||
def _create_message(self, data: MessagePayload, *, thread: Snowflake = MISSING) -> SyncWebhookMessage:
|
||||
state = _WebhookState(self, parent=self._state, thread=thread)
|
||||
# state may be artificial (unlikely at this point...)
|
||||
channel = self.channel or PartialMessageable(state=self._state, id=int(data['channel_id'])) # type: ignore
|
||||
channel = self.channel or PartialMessageable(state=self._state, guild_id=self.guild_id, id=int(data['channel_id'])) # type: ignore
|
||||
# state is artificial
|
||||
return SyncWebhookMessage(data=data, state=state, channel=channel) # type: ignore
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user