mirror of
https://github.com/MelisaDev/melisa.git
synced 2024-11-11 19:07:28 +03:00
embed, but without fields yet and some other changes
This commit is contained in:
parent
1ca2b593e4
commit
cefbf9e7f7
7 changed files with 503 additions and 88 deletions
|
@ -43,7 +43,7 @@ to handle it, which defaults to print a traceback and ignoring the exception.
|
|||
.. note::
|
||||
It will not be received by :meth:`Client.wait_for`.
|
||||
|
||||
:param exception: Produced error.
|
||||
:param exception: Exception.
|
||||
:type exception: :class:`Exception`
|
||||
|
||||
.. function:: on_channel_create(channel)
|
||||
|
@ -112,7 +112,7 @@ to handle it, which defaults to print a traceback and ignoring the exception.
|
|||
See the docs of :attr:`Intents.MESSAGE_CONTENT` for more information.
|
||||
|
||||
:param message: The current message.
|
||||
:type message: :class:`models.message.message.Message
|
||||
:type message: :class:`models.message.message.Message`
|
||||
|
||||
.. function:: on_shard_ready(shard_id)
|
||||
|
||||
|
|
|
@ -55,6 +55,28 @@ class PrivilegedIntentsRequired(ClientException):
|
|||
super().__init__(message.format(self.shard_id))
|
||||
|
||||
|
||||
class EmbedFieldError(MelisaException, ValueError):
|
||||
"""Occurs when an embed field is too large."""
|
||||
|
||||
@classmethod
|
||||
def characters_from_desc(cls, field_type: str, current_size: int, max_size: int):
|
||||
"""Create an instance by description.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
field_type :class:`str`
|
||||
The type/name of the field.
|
||||
current_size :class:`int`
|
||||
The current size of the field.
|
||||
max_si :class:`int`
|
||||
The maximum size of the field.
|
||||
"""
|
||||
return cls(
|
||||
f"{field_type} can have maximum {max_size} characters."
|
||||
f" (Current size: {current_size})"
|
||||
)
|
||||
|
||||
|
||||
class HTTPException(MelisaException):
|
||||
"""Occurs when an HTTP request operation fails."""
|
||||
|
||||
|
|
|
@ -18,6 +18,8 @@ from typing import (
|
|||
)
|
||||
|
||||
from ..message.message import Message
|
||||
from ...exceptions import EmbedFieldError
|
||||
from ...models.message.embed import Embed
|
||||
from ...utils import Snowflake, Timestamp
|
||||
from ...utils import APIModelBase
|
||||
from ...utils.types import APINullable
|
||||
|
@ -502,7 +504,9 @@ class MessageableChannel(Channel):
|
|||
headers={"X-Audit-Log-Reason": reason},
|
||||
)
|
||||
|
||||
async def send(self, content: str = None) -> Message:
|
||||
async def send(
|
||||
self, content: str = None, *, embed: Embed = None, embeds: List[Embed] = None
|
||||
) -> Message:
|
||||
"""|coro|
|
||||
|
||||
Sends a message to the destination with the content given.
|
||||
|
@ -513,6 +517,10 @@ class MessageableChannel(Channel):
|
|||
----------
|
||||
content: Optional[:class:`str`]
|
||||
The content of the message to send.
|
||||
embed: Optional[:class:`~melisa.models.message.embed.Embed`]
|
||||
Embed
|
||||
embeds: Optional[List[:class:`~melisa.models.message.embed.Embed`]]
|
||||
List of embeds
|
||||
|
||||
Raises
|
||||
-------
|
||||
|
@ -526,11 +534,22 @@ class MessageableChannel(Channel):
|
|||
|
||||
# ToDo: Add other parameters
|
||||
|
||||
if embeds is None:
|
||||
embeds = []
|
||||
|
||||
content = str(content) if content is not None else None
|
||||
embeds.append(embed.to_dict()) if embed is not None else None
|
||||
|
||||
for _embed in embeds:
|
||||
if embed.total_length() > 6000:
|
||||
raise EmbedFieldError.characters_from_desc(
|
||||
"Embed", embed.total_length(), 6000
|
||||
)
|
||||
|
||||
return Message.from_dict(
|
||||
await self._http.post(
|
||||
f"/channels/{self.id}/messages", data={"content": content}
|
||||
f"/channels/{self.id}/messages",
|
||||
data={"content": content, "embeds": embeds},
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -169,85 +169,6 @@ class SystemChannelFlags(IntEnum):
|
|||
return self.value
|
||||
|
||||
|
||||
class GuildFeatures(Enum):
|
||||
"""Guild Features
|
||||
|
||||
Attributes
|
||||
----------
|
||||
ANIMATED_ICON:
|
||||
Guild has access to set an animated guild icon
|
||||
BANNER:
|
||||
Guild has access to set a guild banner image
|
||||
COMMERCE:
|
||||
Guild has access to use commerce features (i.e. create store channels)
|
||||
COMMUNITY:
|
||||
Guild can enable welcome screen, Membership Screening,
|
||||
stage channels and discovery, and receives community updates
|
||||
DISCOVERABLE:
|
||||
Guild is able to be discovered in the directory
|
||||
FEATURABLE:
|
||||
Guild is able to be featured in the directory
|
||||
INVITE_SPLASH:
|
||||
Guild has access to set an invite splash background
|
||||
MEMBER_VERIFICATION_GATE_ENABLED:
|
||||
Guild has enabled Membership Screening
|
||||
MONETIZATION_ENABLED:
|
||||
Guild has enabled monetization
|
||||
MORE_STICKERS:
|
||||
Guild has increased custom sticker slots
|
||||
NEWS:
|
||||
Guild has access to create news channels
|
||||
PARTNERED:
|
||||
Guild is partnered
|
||||
PREVIEW_ENABLED:
|
||||
Guild can be previewed before joining via Membership Screening or the directory
|
||||
PRIVATE_THREADS:
|
||||
Guild has access to create private threads
|
||||
ROLE_ICONS:
|
||||
Guild is able to set role icons
|
||||
SEVEN_DAY_THREAD_ARCHIVE:
|
||||
Guild has access to the seven day archive time for threads
|
||||
THREE_DAY_THREAD_ARCHIVE:
|
||||
Guild has access to the three day archive time for threads
|
||||
TICKETED_EVENTS_ENABLED:
|
||||
Guild has enabled ticketed events
|
||||
VANITY_URL:
|
||||
Guild has access to set a vanity URL
|
||||
VERIFIED:
|
||||
Guild is verified
|
||||
VIP_REGIONS:
|
||||
Guild has access to set 384kbps bitrate in voice (previously VIP voice servers)
|
||||
WELCOME_SCREEN_ENABLED:
|
||||
Guild has enabled the welcome screen
|
||||
EXPOSED_TO_ACTIVITIES_WTP_EXPERIMENT:
|
||||
Unkown. Found during testing. Not listed in Discord API docs.
|
||||
"""
|
||||
|
||||
ANIMATED_ICON = "ANIMATED_ICON"
|
||||
BANNER = "BANNER"
|
||||
COMMERCE = "COMMERCE"
|
||||
COMMUNITY = "COMMUNITY"
|
||||
DISCOVERABLE = "DISCOVERABLE"
|
||||
FEATURABLE = "FEATURABLE"
|
||||
INVITE_SPLASH = "INVITE_SPLASH"
|
||||
MEMBER_VERIFICATION_GATE_ENABLED = "MEMBER_VERIFICATION_GATE_ENABLED"
|
||||
MONETIZATION_ENABLED = "MONETIZATION_ENABLED"
|
||||
MORE_STICKERS = "MORE_STICKERS"
|
||||
NEWS = "NEWS"
|
||||
PARTNERED = "PARTNERED"
|
||||
PREVIEW_ENABLED = "PREVIEW_ENABLED"
|
||||
PRIVATE_THREADS = "PRIVATE_THREADS"
|
||||
ROLE_ICONS = "ROLE_ICONS"
|
||||
SEVEN_DAY_THREAD_ARCHIVE = "SEVEN_DAY_THREAD_ARCHIVE"
|
||||
THREE_DAY_THREAD_ARCHIVE = "THREE_DAY_THREAD_ARCHIVE"
|
||||
TICKETED_EVENTS_ENABLED = "TICKETED_EVENTS_ENABLED"
|
||||
VANITY_URL = "VANITY_URL"
|
||||
VERIFIED = "VERIFIED"
|
||||
VIP_REGIONS = "VIP_REGIONS"
|
||||
WELCOME_SCREEN_ENABLED = "WELCOME_SCREEN_ENABLED"
|
||||
EXPOSED_TO_ACTIVITIES_WTP_EXPERIMENT = "EXPOSED_TO_ACTIVITIES_WTP_EXPERIMENT"
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class Guild(APIModelBase):
|
||||
"""Guilds in Discord represent an isolated collection of users and channels,
|
||||
|
@ -289,7 +210,7 @@ class Guild(APIModelBase):
|
|||
Default message notifications level
|
||||
explicit_content_filter: :class:`int`
|
||||
Explicit content filter level
|
||||
features: APINullable[:class:`typing.Any`]
|
||||
features: APINullable[List[:class:`str`]]
|
||||
Enabled guild features
|
||||
roles: APINullable[:class:`typing.Any`]
|
||||
Roles in the guild
|
||||
|
@ -388,7 +309,7 @@ class Guild(APIModelBase):
|
|||
verification_level: APINullable[int] = None
|
||||
default_message_notifications: APINullable[int] = None
|
||||
explicit_content_filter: APINullable[int] = None
|
||||
features: APINullable[List[GuildFeatures]] = None
|
||||
features: APINullable[List[str]] = None
|
||||
roles: APINullable[List] = None
|
||||
emojis: APINullable[List] = None
|
||||
# TODO: Make a structures of emoji and role
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
# Copyright MelisaDev 2022 - Present
|
||||
# Full MIT License can be found in `LICENSE.txt` at the project root.
|
||||
|
||||
from .message import MessageActivityType, MessageFlags, MessageType, Message
|
||||
|
||||
__all__ = ("MessageActivityType", "MessageFlags", "MessageType", "Message")
|
||||
from .message import *
|
||||
from .embed import *
|
||||
|
|
396
melisa/models/message/embed.py
Normal file
396
melisa/models/message/embed.py
Normal file
|
@ -0,0 +1,396 @@
|
|||
# Copyright MelisaDev 2022 - Present
|
||||
# Full MIT License can be found in `LICENSE.txt` at the project root.
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
from datetime import datetime
|
||||
from enum import Enum
|
||||
|
||||
from typing import List, Union, Optional
|
||||
|
||||
from melisa.exceptions import EmbedFieldError
|
||||
from melisa.utils.api_model import APIModelBase, APINullable
|
||||
from melisa.utils.timestamp import Timestamp
|
||||
|
||||
|
||||
class EmbedType(Enum):
|
||||
"""
|
||||
Embed types are "loosely defined" and, for the most part,
|
||||
are not used by our clients for rendering.
|
||||
Embed attributes power what is rendered.
|
||||
Embed types should be considered deprecated and might be removed in a future API version.
|
||||
|
||||
Attributes
|
||||
__________
|
||||
RICH:
|
||||
Generic embed rendered from embed attributes
|
||||
IMAGE
|
||||
Image embed
|
||||
VIDEO
|
||||
Video embed
|
||||
GIFV
|
||||
Animated gif image embed rendered as a video embed
|
||||
ARTICLE
|
||||
Article embed
|
||||
LINK
|
||||
Link embed
|
||||
"""
|
||||
|
||||
RICH = "rich"
|
||||
IMAGE = "image"
|
||||
VIDEO = "video"
|
||||
GIFV = "gifv"
|
||||
ARTICLE = "article"
|
||||
LINK = "link"
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class EmbedThumbnail(APIModelBase):
|
||||
"""Representation of the Embed Thumbnail
|
||||
|
||||
Attributes
|
||||
----------
|
||||
url: :class:`str`
|
||||
Source url of the thumbnail
|
||||
proxy_url: Optional[:class:`str`]
|
||||
A proxied url of the thumbnail
|
||||
height: Optional[:class:`int`]
|
||||
Height of the thumbnail
|
||||
width: Optional[:class:`int`]
|
||||
Width of the thumbnail
|
||||
"""
|
||||
|
||||
url: str
|
||||
proxy_url: APINullable[str] = None
|
||||
height: APINullable[int] = None
|
||||
width: APINullable[int] = None
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class EmbedVideo(APIModelBase):
|
||||
"""Representation of the Embed Video
|
||||
|
||||
Attributes
|
||||
----------
|
||||
url: Optional[:class:`str`]
|
||||
Source url of the video
|
||||
proxy_url: Optional[:class:`str`]
|
||||
A proxied url of the video
|
||||
height: Optional[:class:`int`]
|
||||
Height of the video
|
||||
width: Optional[:class:`int`]
|
||||
Width of the video
|
||||
"""
|
||||
|
||||
url: str
|
||||
proxy_url: APINullable[str] = None
|
||||
height: APINullable[int] = None
|
||||
width: APINullable[int] = None
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class EmbedImage(APIModelBase):
|
||||
"""Representation of the Embed Image
|
||||
|
||||
Attributes
|
||||
----------
|
||||
url: :class:`str`
|
||||
Source url of image (only supports http(s) and attachments)
|
||||
proxy_url: Optional[:class:`str`]
|
||||
A proxied url of the image
|
||||
height: Optional[:class:`int`]
|
||||
Height of the image
|
||||
width: Optional[:class:`int`]
|
||||
Width of the image
|
||||
"""
|
||||
|
||||
url: str
|
||||
proxy_url: APINullable[str] = None
|
||||
height: APINullable[int] = None
|
||||
width: APINullable[int] = None
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class EmbedProvider(APIModelBase):
|
||||
"""Representation of the Embed Provider
|
||||
|
||||
Attributes
|
||||
----------
|
||||
name: Optional[:class:`str`]
|
||||
Name of provider
|
||||
url: Optional[:class:`str`]
|
||||
Url of provider
|
||||
"""
|
||||
|
||||
name: APINullable[str] = None
|
||||
url: APINullable[str] = None
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class EmbedAuthor(APIModelBase):
|
||||
"""Representation of the Embed Author
|
||||
|
||||
Attributes
|
||||
----------
|
||||
name: :class:`str`
|
||||
Name of author
|
||||
url: Optional[:class:`str`]
|
||||
Url of author
|
||||
icon_url: Optional[:class:`str`]
|
||||
Url of author icon (only supports http(s) and attachments)
|
||||
proxy_icon_url: Optional[:class:`str`]
|
||||
A proxied url of author icon
|
||||
"""
|
||||
|
||||
name: str
|
||||
url: APINullable[str] = None
|
||||
icon_url: APINullable[str] = None
|
||||
proxy_icon_url: APINullable[str] = None
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class EmbedFooter(APIModelBase):
|
||||
"""Representation of the Embed Footer
|
||||
|
||||
Attributes
|
||||
----------
|
||||
text: :class:`str`
|
||||
Footer text
|
||||
icon_url: Optional[:class:`str`]
|
||||
Url of footer icon (only supports http(s) and attachments)
|
||||
proxy_icon_url: Optional[:class:`str`]
|
||||
A proxied url of footer icon
|
||||
"""
|
||||
|
||||
text: str
|
||||
icon_url: APINullable[str] = None
|
||||
proxy_icon_url: APINullable[str] = None
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class EmbedField(APIModelBase):
|
||||
"""Representation of the Embed Field
|
||||
|
||||
Attributes
|
||||
----------
|
||||
name: :class:`str`
|
||||
Name of the field
|
||||
value: :class:`str`
|
||||
Value of the field
|
||||
inline: Optional[:class:`bool`]
|
||||
Whether or not this field should display inline
|
||||
"""
|
||||
|
||||
name: str
|
||||
value: str
|
||||
inline: APINullable[str] = None
|
||||
|
||||
|
||||
@dataclass(repr=False)
|
||||
class Embed(APIModelBase):
|
||||
# ToDo: Add fields set method
|
||||
|
||||
"""Represents an embed sent in with message within Discord.
|
||||
|
||||
Attributes
|
||||
----------
|
||||
|
||||
title: Optional[:class:`str`]
|
||||
Title of embed
|
||||
type: Optional[:class:`~melisa.models.message.embed.EmbedType`]
|
||||
Type of embed (always "rich" for webhook embeds)
|
||||
description: Optional[:class:`str`]
|
||||
Description of embed
|
||||
color: Optional[:class:`int`]
|
||||
Color code of the embed
|
||||
fields: Optional[List[:class:`~melisa.models.message.embed.EmbedField`]]
|
||||
Fields information.
|
||||
footer: Optional[:class:`~melisa.models.message.embed.EmbedFooter`]
|
||||
Footer information.
|
||||
image: Optional[:class:`~melisa.models.message.embed.EmbedImage`]
|
||||
Image information.
|
||||
provider: Optional[:class:`~melisa.models.message.embed.EmbedProvider`]
|
||||
Provider information.
|
||||
thumbnail: Optional[:class:`~melisa.models.message.embed.EmbedThumbnail`]
|
||||
Thumbnail information.
|
||||
timestamp: Optional[:class:`~melisa.utils.timestamp.Timestamp`]
|
||||
Timestamp of embed content
|
||||
url: Optional[:class:`str`]
|
||||
Url of embed
|
||||
video: Optional[:class:`~melisa.models.message.embed.EmbedVideo`]
|
||||
Video information.
|
||||
"""
|
||||
|
||||
title: APINullable[str] = None
|
||||
type: APINullable[EmbedType] = None
|
||||
description: APINullable[str] = None
|
||||
url: APINullable[str] = None
|
||||
timestamp: APINullable[Timestamp] = None
|
||||
color: APINullable[int] = None
|
||||
footer: APINullable[EmbedFooter] = None
|
||||
image: APINullable[EmbedImage] = None
|
||||
thumbnail: APINullable[EmbedThumbnail] = None
|
||||
video: APINullable[EmbedVideo] = None
|
||||
provider: APINullable[EmbedProvider] = None
|
||||
author: APINullable[EmbedAuthor] = None
|
||||
fields: APINullable[List[EmbedField]] = None
|
||||
|
||||
def __post_init__(self):
|
||||
if self.title and len(self.title) > 256:
|
||||
raise EmbedFieldError.characters_from_desc(
|
||||
"Embed Title",
|
||||
len(self.title),
|
||||
256,
|
||||
)
|
||||
|
||||
if self.description and len(self.description) > 4096:
|
||||
raise EmbedFieldError.characters_from_desc(
|
||||
"Embed Description", len(self.description), 4096
|
||||
)
|
||||
|
||||
if self.fields and len(self.fields) > 25:
|
||||
raise EmbedFieldError("""You can't set more than 25 embed fields!""")
|
||||
|
||||
def set_timestamp(self, time: Union[Timestamp, datetime]) -> Embed:
|
||||
"""Sets timestamp in the supported by discord format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
time: :class:`~melisa.utils.timestamp.Timestamp`
|
||||
The datetime to set the timestamp to.
|
||||
|
||||
Returns
|
||||
-------
|
||||
:class:`~,e;osa.models.message.embed.Embed`
|
||||
The new embed object.
|
||||
"""
|
||||
self.timestamp = time.isoformat()
|
||||
|
||||
return self
|
||||
|
||||
def set_author(
|
||||
self,
|
||||
name: str,
|
||||
*,
|
||||
url: Optional[str] = None,
|
||||
icon_url: Optional[str] = None,
|
||||
proxy_icon_url: Optional[str] = None,
|
||||
) -> Embed:
|
||||
"""Set the author for the embed.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name: :class:`str`
|
||||
Name of author
|
||||
url: Optional[:class:`str`]
|
||||
Url of author icon (only supports http(s) and attachments)
|
||||
icon_url: Optional[:class:`str`]
|
||||
Url of author
|
||||
proxy_icon_url: Optional[:class:`str`]
|
||||
A proxied url of author icon
|
||||
Returns
|
||||
-------
|
||||
:class:`~melisa.models.message.embed.Embed`
|
||||
Updated embed.
|
||||
"""
|
||||
|
||||
self.author = EmbedAuthor(
|
||||
name=name,
|
||||
url=url,
|
||||
icon_url=icon_url,
|
||||
proxy_icon_url=proxy_icon_url,
|
||||
)
|
||||
|
||||
return self
|
||||
|
||||
def set_image(self, url: str, *, proxy_url: Optional[str] = None) -> Embed:
|
||||
"""Set the image for the embed.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
url: :class:`str`
|
||||
Source url of image (only supports http(s) and attachments)
|
||||
proxy_url: Optional[:class:`str`]
|
||||
A proxied url of the image
|
||||
Returns
|
||||
-------
|
||||
:class:`~melisa.models.message.embed.Embed`
|
||||
Updated embed.
|
||||
"""
|
||||
|
||||
self.image = EmbedImage(url=url, proxy_url=proxy_url)
|
||||
|
||||
return self
|
||||
|
||||
def set_thumbnail(self, url: str, *, proxy_url: Optional[str] = None) -> Embed:
|
||||
"""Set the thumbnail for the embed.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
url: :class:`str`
|
||||
Source url of thumbnail (only supports http(s) and attachments)
|
||||
proxy_url: Optional[:class:`str`]
|
||||
A proxied url of the thumbnail
|
||||
Returns
|
||||
-------
|
||||
:class:`~melisa.models.message.embed.Embed`
|
||||
Updated embed.
|
||||
"""
|
||||
|
||||
self.thumbnail = EmbedThumbnail(url=url, proxy_url=proxy_url)
|
||||
|
||||
return self
|
||||
|
||||
def set_footer(
|
||||
self,
|
||||
text: str,
|
||||
*,
|
||||
icon_url: Optional[str] = None,
|
||||
proxy_icon_url: Optional[str] = None,
|
||||
) -> Embed:
|
||||
"""
|
||||
Sets the embed footer.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
text: :class:`str`
|
||||
Footer text
|
||||
icon_url: Optional[:class:`str`]
|
||||
Url of footer icon (only supports http(s) and attachments)
|
||||
proxy_icon_url: Optional[:class:`str`]
|
||||
A proxied url of footer icon
|
||||
|
||||
Returns
|
||||
-------
|
||||
:class:`~melisa.models.message.embed.Embed`
|
||||
Updated embed.
|
||||
"""
|
||||
self.footer = EmbedFooter(
|
||||
text=text, icon_url=icon_url, proxy_icon_url=proxy_icon_url
|
||||
)
|
||||
|
||||
return self
|
||||
|
||||
def total_length(self) -> int:
|
||||
"""Get the total character count of the embed.
|
||||
|
||||
Returns
|
||||
-------
|
||||
:class:`int`
|
||||
The total character count of this embed, including title, description,
|
||||
fields, footer, and author combined.
|
||||
"""
|
||||
total = len(self.title or "") + len(self.description or "")
|
||||
|
||||
if self.fields:
|
||||
for field in self.fields:
|
||||
total += len(field.name) + len(field.value)
|
||||
|
||||
if self.footer and self.footer.text:
|
||||
total += len(self.footer.text)
|
||||
|
||||
if self.author and self.author.name:
|
||||
total += len(self.author.name)
|
||||
|
||||
return total
|
58
tests/test_embeds.py
Normal file
58
tests/test_embeds.py
Normal file
|
@ -0,0 +1,58 @@
|
|||
import datetime
|
||||
|
||||
from melisa import Embed, Timestamp
|
||||
|
||||
dict_embed = {
|
||||
'title': 'my title',
|
||||
'description': 'simple description',
|
||||
'timestamp': datetime.datetime.utcfromtimestamp(1649748784).isoformat(),
|
||||
'footer': {
|
||||
'text': 'cool footer text'
|
||||
},
|
||||
'author': {
|
||||
'name': 'best author'
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class TestEmbed:
|
||||
def test_total_length_when_embed_is_empty(self):
|
||||
embed = Embed()
|
||||
assert embed.total_length() == 0
|
||||
|
||||
def test_total_length_when_title_is_none(self):
|
||||
embed = Embed(title=None)
|
||||
assert embed.total_length() == 0
|
||||
|
||||
def test_total_length_title(self):
|
||||
embed = Embed(title="my title")
|
||||
assert embed.total_length() == 8
|
||||
|
||||
def test_total_length_when_description_is_none(self):
|
||||
embed = Embed(description=None)
|
||||
assert embed.total_length() == 0
|
||||
|
||||
def test_total_length_description(self):
|
||||
embed = Embed(description="simple description")
|
||||
assert embed.total_length() == 18
|
||||
|
||||
def test_total_length_author_name(self):
|
||||
embed = Embed().set_author(name="best author")
|
||||
assert embed.total_length() == 11
|
||||
|
||||
def test_total_length_footer_text(self):
|
||||
embed = Embed().set_footer(text="cool footer text")
|
||||
assert embed.total_length() == 16
|
||||
|
||||
def test_total_length_all(self):
|
||||
embed = Embed(title="my title", description="simple description")
|
||||
embed.set_author(name="best author")
|
||||
embed.set_footer(text="cool footer text")
|
||||
assert embed.total_length() == 53
|
||||
|
||||
def test_comparing_embeds(self):
|
||||
embed = Embed(title="my title", description="simple description")
|
||||
embed.set_author(name="best author")
|
||||
embed.set_footer(text="cool footer text")
|
||||
embed.set_timestamp(Timestamp.parse(1649748784))
|
||||
assert embed.to_dict() == dict_embed
|
Loading…
Reference in a new issue