Browse Source

chore: Donnot subclass AttachmentBase and fake payload for Attachment initialization on UnfurledAttachment

pull/10166/head
DA-344 3 months ago
parent
commit
4467ebaca6
  1. 221
      discord/attachment.py

221
discord/attachment.py

@ -52,9 +52,87 @@ __all__ = (
)
class AttachmentBase:
class Attachment(Hashable):
"""Represents an attachment from Discord.
.. container:: operations
.. describe:: str(x)
Returns the URL of the attachment.
.. describe:: x == y
Checks if the attachment is equal to another attachment.
.. describe:: x != y
Checks if the attachment is not equal to another attachment.
.. describe:: hash(x)
Returns the hash of the attachment.
.. versionchanged:: 1.7
Attachment can now be casted to :class:`str` and is hashable.
Attributes
------------
id: :class:`int`
The attachment ID.
size: :class:`int`
The attachment size in bytes.
height: Optional[:class:`int`]
The attachment's height, in pixels. Only applicable to images and videos.
width: Optional[:class:`int`]
The attachment's width, in pixels. Only applicable to images and videos.
filename: :class:`str`
The attachment's filename.
url: :class:`str`
The attachment URL. If the message this attachment was attached
to is deleted, then this will 404.
proxy_url: :class:`str`
The proxy URL. This is a cached version of the :attr:`~Attachment.url` in the
case of images. When the message is deleted, this URL might be valid for a few
minutes or not valid at all.
content_type: Optional[:class:`str`]
The attachment's `media type <https://en.wikipedia.org/wiki/Media_type>`_
.. versionadded:: 1.7
description: Optional[:class:`str`]
The attachment's description. Only applicable to images.
.. versionadded:: 2.0
ephemeral: :class:`bool`
Whether the attachment is ephemeral.
.. versionadded:: 2.0
duration: Optional[:class:`float`]
The duration of the audio file in seconds. Returns ``None`` if it's not a voice message.
.. versionadded:: 2.3
waveform: Optional[:class:`bytes`]
The waveform (amplitudes) of the audio in bytes. Returns ``None`` if it's not a voice message.
.. versionadded:: 2.3
title: Optional[:class:`str`]
The normalised version of the attachment's filename.
.. versionadded:: 2.5
spoiler: :class:`bool`
Whether the attachment is a spoiler or not. Unlike :meth:`.is_spoiler`, this uses the API returned
data.
.. versionadded:: 2.6
"""
__slots__ = (
'id',
'size',
'ephemeral',
'duration',
'waveform',
'title',
'url',
'proxy_url',
'description',
@ -68,7 +146,13 @@ class AttachmentBase:
'_state',
)
def __init__(self, data: AttachmentBasePayload, state: Optional[ConnectionState]) -> None:
def __init__(self, *, data: AttachmentPayload, state: Optional[ConnectionState]):
self.id: int = int(data['id'])
self.filename: str = data['filename']
self.size: int = data['size']
self.ephemeral: bool = data.get('ephemeral', False)
self.duration: Optional[float] = data.get('duration_secs')
self.title: Optional[str] = data.get('title')
self._state: Optional[ConnectionState] = state
self._http: Optional[HTTPClient] = state.http if state else None
self.url: str = data['url']
@ -248,11 +332,25 @@ class AttachmentBase:
spoiler=spoiler,
)
def to_dict(self) -> AttachmentBasePayload:
base: AttachmentBasePayload = {
def is_spoiler(self) -> bool:
""":class:`bool`: Whether this attachment contains a spoiler."""
return self.spoiler or self.filename.startswith('SPOILER_')
def is_voice_message(self) -> bool:
""":class:`bool`: Whether this attachment is a voice message."""
return self.duration is not None and 'voice-message' in self.url
def __repr__(self) -> str:
return f'<Attachment id={self.id} filename={self.filename!r} url={self.url!r}>'
def to_dict(self) -> AttachmentPayload:
base: AttachmentPayload = {
'url': self.url,
'proxy_url': self.proxy_url,
'spoiler': self.spoiler,
'id': self.id,
'filename': self.filename,
'size': self.size,
}
if self.width:
@ -265,118 +363,7 @@ class AttachmentBase:
return base
class Attachment(Hashable, AttachmentBase):
"""Represents an attachment from Discord.
.. container:: operations
.. describe:: str(x)
Returns the URL of the attachment.
.. describe:: x == y
Checks if the attachment is equal to another attachment.
.. describe:: x != y
Checks if the attachment is not equal to another attachment.
.. describe:: hash(x)
Returns the hash of the attachment.
.. versionchanged:: 1.7
Attachment can now be casted to :class:`str` and is hashable.
Attributes
------------
id: :class:`int`
The attachment ID.
size: :class:`int`
The attachment size in bytes.
height: Optional[:class:`int`]
The attachment's height, in pixels. Only applicable to images and videos.
width: Optional[:class:`int`]
The attachment's width, in pixels. Only applicable to images and videos.
filename: :class:`str`
The attachment's filename.
url: :class:`str`
The attachment URL. If the message this attachment was attached
to is deleted, then this will 404.
proxy_url: :class:`str`
The proxy URL. This is a cached version of the :attr:`~Attachment.url` in the
case of images. When the message is deleted, this URL might be valid for a few
minutes or not valid at all.
content_type: Optional[:class:`str`]
The attachment's `media type <https://en.wikipedia.org/wiki/Media_type>`_
.. versionadded:: 1.7
description: Optional[:class:`str`]
The attachment's description. Only applicable to images.
.. versionadded:: 2.0
ephemeral: :class:`bool`
Whether the attachment is ephemeral.
.. versionadded:: 2.0
duration: Optional[:class:`float`]
The duration of the audio file in seconds. Returns ``None`` if it's not a voice message.
.. versionadded:: 2.3
waveform: Optional[:class:`bytes`]
The waveform (amplitudes) of the audio in bytes. Returns ``None`` if it's not a voice message.
.. versionadded:: 2.3
title: Optional[:class:`str`]
The normalised version of the attachment's filename.
.. versionadded:: 2.5
spoiler: :class:`bool`
Whether the attachment is a spoiler or not. Unlike :meth:`.is_spoiler`, this uses the API returned
data.
.. versionadded:: 2.6
"""
__slots__ = (
'id',
'size',
'ephemeral',
'duration',
'waveform',
'title',
)
def __init__(self, *, data: AttachmentPayload, state: ConnectionState):
self.id: int = int(data['id'])
self.filename: str = data['filename']
self.size: int = data['size']
self.ephemeral: bool = data.get('ephemeral', False)
self.duration: Optional[float] = data.get('duration_secs')
self.title: Optional[str] = data.get('title')
super().__init__(data, state)
def is_spoiler(self) -> bool:
""":class:`bool`: Whether this attachment contains a spoiler."""
return self.spoiler or self.filename.startswith('SPOILER_')
def is_voice_message(self) -> bool:
""":class:`bool`: Whether this attachment is a voice message."""
return self.duration is not None and 'voice-message' in self.url
def __repr__(self) -> str:
return f'<Attachment id={self.id} filename={self.filename!r} url={self.url!r}>'
def to_dict(self) -> AttachmentPayload:
result: AttachmentPayload = super().to_dict() # pyright: ignore[reportAssignmentType]
result['id'] = self.id
result['filename'] = self.filename
result['size'] = self.size
return result
class UnfurledAttachment(AttachmentBase):
class UnfurledAttachment(Attachment):
"""Represents an unfurled attachment item from a :class:`Component`.
.. versionadded:: 2.6
@ -425,7 +412,7 @@ class UnfurledAttachment(AttachmentBase):
def __init__(self, data: UnfurledAttachmentPayload, state: Optional[ConnectionState]) -> None:
self.loading_state: MediaLoadingState = try_enum(MediaLoadingState, data.get('loading_state', 0))
super().__init__(data, state)
super().__init__(data={'id': 0, 'filename': '', 'size': 0, **data}, state=state) # type: ignore
def __repr__(self) -> str:
return f'<UnfurledAttachment url={self.url!r}>'

Loading…
Cancel
Save