Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(embed): add the ability to pass disnake.File to more Embed methods #1229

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions changelog/1184.feature.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add the possibility to pass :class:`disnake.File` objects to :meth:`~Embed.set_author` and :meth:`~Embed.set_icon`.
91 changes: 81 additions & 10 deletions disnake/embeds.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class _EmbedAuthorProxy(Sized, Protocol):
icon_url: Optional[str]
proxy_icon_url: Optional[str]

_FileKey = Literal["image", "thumbnail"]
_FileKey = Literal["image", "thumbnail", "footer", "author"]


class Embed:
Expand Down Expand Up @@ -385,12 +385,33 @@ def footer(self) -> _EmbedFooterProxy:
"""
return cast("_EmbedFooterProxy", EmbedProxy(self._footer))

def set_footer(self, *, text: Any, icon_url: Optional[Any] = None) -> Self:
@overload
def set_footer(self, *, text: Any, icon_url: Optional[Any] = ...) -> Self:
...

@overload
def set_footer(self, *, text: Any, file: File = ...) -> Self:
...

def set_footer(
self, *, text: Any, icon_url: Optional[Any] = MISSING, file: File = MISSING
) -> Self:
"""Sets the footer for the embed content.

This function returns the class instance to allow for fluent-style
chaining.

Exactly one of ``icon_url`` or ``file`` should be passed at a time, if passed.

.. warning::
Passing a :class:`disnake.File` object will make the embed not
reusable.

.. note::
If used with the other ``set_*`` methods you must ensure
that the :attr:`.File.filename` is different than the other file(s)
that you are passing.

Parameters
----------
text: :class:`str`
Expand All @@ -401,13 +422,18 @@ def set_footer(self, *, text: Any, icon_url: Optional[Any] = None) -> Self:

icon_url: Optional[:class:`str`]
The URL of the footer icon. Only HTTP(S) is supported.
file: :class:`File`
The file to use as the image.

.. versionadded:: 2.10
"""
self._footer = {
"text": str(text),
}

if icon_url is not None:
self._footer["icon_url"] = str(icon_url)
result = self._handle_resource(icon_url, file, key="footer", required=False)
if result is not None:
self._footer["icon_url"] = result

return self

Expand Down Expand Up @@ -457,6 +483,11 @@ def set_image(self, url: Optional[Any] = MISSING, *, file: File = MISSING) -> Se
Passing a :class:`disnake.File` object will make the embed not
reusable.

.. note::
If used with the other ``set_*`` methods you must ensure
that the :attr:`.File.filename` is different than the other file(s)
that you are passing.

.. versionchanged:: 1.4
Passing ``None`` removes the image.

Expand Down Expand Up @@ -508,6 +539,11 @@ def set_thumbnail(self, url: Optional[Any] = MISSING, *, file: File = MISSING) -
Passing a :class:`disnake.File` object will make the embed not
reusable.

.. note::
If used with the other ``set_*`` methods you must ensure
that the :attr:`.File.filename` is different than the other file(s)
that you are passing.

.. versionchanged:: 1.4
Passing ``None`` removes the thumbnail.

Expand Down Expand Up @@ -559,18 +595,40 @@ def author(self) -> _EmbedAuthorProxy:
"""
return cast("_EmbedAuthorProxy", EmbedProxy(self._author))

@overload
def set_author(
self, *, name: Any, url: Optional[Any] = ..., icon_url: Optional[Any] = ...
) -> Self:
...

@overload
def set_author(self, *, name: Any, url: Optional[Any] = ..., file: File = ...) -> Self:
...

def set_author(
self,
*,
name: Any,
url: Optional[Any] = None,
icon_url: Optional[Any] = None,
icon_url: Optional[Any] = MISSING,
file: File = MISSING,
) -> Self:
"""Sets the author for the embed content.

This function returns the class instance to allow for fluent-style
chaining.

Exactly one of ``icon_url`` or ``file`` should be passed at a time, if passed.

.. warning::
Passing a :class:`disnake.File` object will make the embed not
reusable.

.. note::
If used with the other ``set_*`` methods you must ensure
that the :attr:`.File.filename` is different than the other file(s)
that you are passing.

Parameters
----------
name: :class:`str`
Expand All @@ -579,6 +637,10 @@ def set_author(
The URL for the author.
icon_url: Optional[:class:`str`]
The URL of the author icon. Only HTTP(S) is supported.
file: :class:`File`
The file to use as the image.

.. versionadded:: 2.10
"""
self._author = {
"name": str(name),
Expand All @@ -587,8 +649,11 @@ def set_author(
if url is not None:
self._author["url"] = str(url)

if icon_url is not None:
self._author["icon_url"] = str(icon_url)
result = self._handle_resource(
icon_url if icon_url else None, file, key="author", required=False
)
if result is not None:
self._author["icon_url"] = result

return self

Expand Down Expand Up @@ -821,9 +886,15 @@ def get_default_colour(cls) -> Optional[Colour]:

get_default_color = get_default_colour

def _handle_resource(self, url: Optional[Any], file: File, *, key: _FileKey) -> Optional[str]:
if not (url is MISSING) ^ (file is MISSING):
raise TypeError("Exactly one of url or file must be provided")
def _handle_resource(
self, url: Optional[Any], file: File, *, key: _FileKey, required: bool = True
) -> Optional[str]:
if required:
if not (url is MISSING) ^ (file is MISSING):
raise TypeError("Exactly one of url or file must be provided")
else:
if url is not MISSING and file is not MISSING:
raise TypeError("Only one of url or file must be provided, not both.")

if file:
if file.filename is None:
Expand Down
Loading