Rewrite Asset design

This is a breaking change.

This does the following transformations, assuming `asset` represents
an asset type.

Object.is_asset_animated() => Object.asset.is_animated()
Object.asset => Object.asset.key
Object.asset_url => Object.asset_url
Object.asset_url_as => Object.asset.replace(...)

Since the asset type now requires a key (or hash, if you will),
Emoji had to be flattened similar to how Attachment was done since
these assets are keyed solely ID.

Emoji.url (Asset) => Emoji.url (str)
Emoji.url_as => removed
Emoji.url.read => Emoji.read
Emoji.url.save => Emoji.save

This transformation was also done to PartialEmoji.
This commit is contained in:
Rapptz
2021-04-16 11:21:13 -04:00
parent 57dbb37a52
commit 9eaf1e85e4
14 changed files with 488 additions and 726 deletions

View File

@ -22,7 +22,10 @@ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
"""
import io
from .asset import Asset
from .errors import DiscordException, InvalidArgument
from . import utils
__all__ = (
@ -149,44 +152,83 @@ class PartialEmoji(_EmojiTag):
return utils.snowflake_time(self.id)
@property
def url(self):
""":class:`Asset`: Returns the asset of the emoji, if it is custom.
def url(self) -> str:
""":class:`str`: Returns the URL of the emoji, if it is custom.
This is equivalent to calling :meth:`url_as` with
the default parameters (i.e. png/gif detection).
If this isn't a custom emoji then an empty string is returned
"""
return self.url_as(format=None)
if self.is_unicode_emoji():
return ''
def url_as(self, *, format=None, static_format="png"):
"""Returns an :class:`Asset` for the emoji's url, if it is custom.
fmt = 'gif' if self.animated else 'png'
return f'{Asset.BASE}/emojis/{self.id}.{fmt}'
The format must be one of 'webp', 'jpeg', 'jpg', 'png' or 'gif'.
'gif' is only valid for animated emojis.
async def read(self):
"""|coro|
.. versionadded:: 1.7
Retrieves the content of this emoji as a :class:`bytes` object.
Parameters
-----------
format: Optional[:class:`str`]
The format to attempt to convert the emojis to.
If the format is ``None``, then it is automatically
detected as either 'gif' or static_format, depending on whether the
emoji is animated or not.
static_format: Optional[:class:`str`]
Format to attempt to convert only non-animated emoji's to.
Defaults to 'png'
.. versionadded:: 2.0
Raises
-------
------
DiscordException
There was no internal connection state.
InvalidArgument
Bad image format passed to ``format`` or ``static_format``.
The emoji isn't custom.
HTTPException
Downloading the emoji failed.
NotFound
The emoji was deleted.
Returns
-------
:class:`bytes`
The content of the emoji.
"""
if self._state is None:
raise DiscordException('Invalid state (no ConnectionState provided)')
if self.is_unicode_emoji():
raise InvalidArgument('PartialEmoji is not a custom emoji')
return await self._state.http.get_from_cdn(self.url)
async def save(self, fp, *, seek_begin=True):
"""|coro|
Saves this emoji into a file-like object.
.. versionadded:: 2.0
Parameters
----------
fp: Union[BinaryIO, :class:`os.PathLike`]
Same as in :meth:`Attachment.save`.
seek_begin: :class:`bool`
Same as in :meth:`Attachment.save`.
Raises
------
DiscordException
There was no internal connection state.
HTTPException
Downloading the emoji failed.
NotFound
The emoji was deleted.
Returns
--------
:class:`Asset`
The resulting CDN asset.
:class:`int`
The number of bytes written.
"""
if self.is_unicode_emoji():
return Asset(self._state)
return Asset._from_emoji(self._state, self, format=format, static_format=static_format)
data = await self.read()
if isinstance(fp, io.IOBase) and fp.writable():
written = fp.write(data)
if seek_begin:
fp.seek(0)
return written
else:
with open(fp, 'wb') as f:
return f.write(data)