hikari.emojis
Application and entities that are used to describe emojis on Discord.
View Source
# -*- coding: utf-8 -*- # cython: language_level=3 # Copyright (c) 2020 Nekokatt # Copyright (c) 2021-present davfsa # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """Application and entities that are used to describe emojis on Discord.""" from __future__ import annotations __all__: typing.Sequence[str] = ("Emoji", "UnicodeEmoji", "CustomEmoji", "KnownCustomEmoji") import abc import re import typing import attr from hikari import files from hikari import snowflakes from hikari import urls from hikari.internal import attr_extensions from hikari.internal import routes # import unicodedata if typing.TYPE_CHECKING: from hikari import traits from hikari import users _TWEMOJI_PNG_BASE_URL: typing.Final[str] = "https://raw.githubusercontent.com/twitter/twemoji/master/assets/72x72/" _CUSTOM_EMOJI_REGEX: typing.Final[typing.Pattern[str]] = re.compile(r"<(?P<flags>[^:]*):(?P<name>[^:]*):(?P<id>\d+)>") class Emoji(files.WebResource, abc.ABC): """Base class for all emojis. Any emoji implementation supports being used as a `hikari.files.Resource` when uploading an attachment to the API. This is achieved in the same way as using a `hikari.files.WebResource` would achieve this. """ __slots__: typing.Sequence[str] = () @property @abc.abstractmethod def name(self) -> str: """Return the generic name/representation for this emoji.""" @property @abc.abstractmethod def url(self) -> str: """URL of the emoji image to display in clients.""" @property @abc.abstractmethod def url_name(self) -> str: """Name of the part of the emoji to use in requests.""" @property @abc.abstractmethod def mention(self) -> str: """Mention string to use to mention the emoji with.""" @classmethod def parse(cls, string: str, /) -> Emoji: """Parse a given string into an emoji object. Parameters ---------- string : str The emoji object to parse. Returns ------- Emoji The parsed emoji object. This will be a `CustomEmoji` if a custom emoji mention, or a `UnicodeEmoji` otherwise. Raises ------ ValueError If a mention is given that has an invalid format. """ if string.startswith("<") and string.endswith(">"): return CustomEmoji.parse(string) return UnicodeEmoji.parse(string) class UnicodeEmoji(str, Emoji): """Represents a unicode emoji. .. warning:: A word of warning if you try to upload this emoji as a file attachment. While this emoji type can be used to upload the Twemoji representations of this emoji as a PNG, this is NOT foolproof. The mapping between Discord's implementation and official Twemoji bindings is very flaky. Responsible implementations relying on this behaviour will be implemented to expect this behaviour in the form of `hikari.errors.NotFoundError` exceptions being raised when a mismatch may occur. It is also likely that this will change in the future without notice, so you will likely be relying on flaky behaviour. If this is proven to be too unstable, this functionality will be removed in a future release after a deprecation period. """ __slots__: typing.Sequence[str] = () @property def name(self) -> str: """Return the code points which form the emoji.""" return self @property @typing.final def url_name(self) -> str: return self @property def mention(self) -> str: return self @property @typing.final def codepoints(self) -> typing.Sequence[int]: """Integer codepoints that make up this emoji, as UTF-8.""" return [ord(c) for c in self] @property def filename(self) -> str: """Filename to use if re-uploading this emoji's PNG.""" codepoints = self.codepoints # It looks like the rule is to delete character #2 if the value # of this is 0xfe0f and the character is up to 4 characters long. # Other than that, the mapping is 1-to-1. There's a couple of outliers # to this 0xfe0f rule and they seem to follow a pattern where the # codepoint after 0xfe0f is 0x200D but this might be a coincidence and # if Discord start breaking this regularly I might need to ask for a # more permanent solution. This is provisionally provided. If we find it # breaks in other ways, I will just revoke this functionality in a # future update. if codepoints[1:2] == [0xFE0F] and len(codepoints) <= 4 and codepoints[2:3] != [0x200D]: codepoints = [codepoints[0], *codepoints[2:]] return "-".join(hex(c)[2:] for c in codepoints) + ".png" @property def url(self) -> str: """Get the URL of the PNG rendition of this emoji. This will use the official Twitter "twemoji" repository to fetch this information, as Discord only stores this in a hashed format that uses SVG files, which is not usually of any use. Since this uses "twemoji" directly, the emojis may not directly match what is on Discord if Discord have failed to keep their emoji packs up-to-date with this repository. Example ------- ```py >>> emoji = hikari.UnicodeEmoji("\N{OK HAND SIGN}") >>> emoji.url 'https://raw.githubusercontent.com/twitter/twemoji/master/assets/72x72/1f44c.png' ``` """ return _TWEMOJI_PNG_BASE_URL + self.filename # @property # @typing.final # def unicode_names(self) -> typing.Sequence[str]: # """Get the unicode name of the emoji as a sequence. # # This returns the name of each codepoint. If only one codepoint exists, # then this will only have one item in the resulting sequence. # """ # return [unicodedata.name(c) for c in self] @property @typing.final def unicode_escape(self) -> str: """Get the unicode escape string for this emoji.""" return bytes(self, "unicode_escape").decode("utf-8") @classmethod @typing.final def parse_codepoints(cls, codepoint: int, *codepoints: int) -> UnicodeEmoji: """Create a unicode emoji from one or more UTF-32 codepoints.""" return cls("".join(map(chr, (codepoint, *codepoints)))) @classmethod @typing.final def parse_unicode_escape(cls, escape: str) -> UnicodeEmoji: """Create a unicode emoji from a unicode escape string.""" return cls(escape.encode("utf-8"), "unicode_escape") @classmethod @typing.final def parse(cls, string: str, /) -> UnicodeEmoji: """Parse a given string into a unicode emoji object. Parameters ---------- string : str The emoji object to parse. Returns ------- UnicodeEmoji The parsed UnicodeEmoji object. """ # TODO: Re-add validity # Ensure validity. # for i, codepoint in enumerate(string, start=1): # unicodedata.name(codepoint) return cls(string) @attr_extensions.with_copy @attr.define(hash=True, kw_only=True, weakref_slot=False) class CustomEmoji(snowflakes.Unique, Emoji): """Represents a custom emoji. This is a custom emoji that is from a guild you might not be part of. All CustomEmoji objects and their derivatives act as valid `hikari.files.Resource` objects. This means you can use them as a file when sending a message. >>> emojis = await bot.rest.fetch_guild_emojis(12345) >>> picks = random.choices(emojis, 5) >>> await event.respond(files=picks) .. warning:: Discord will not provide information on whether these emojis are animated or not when a reaction is removed and an event is fired. This is problematic if you need to try and determine the emoji that was removed. The side effect of this means that mentions for animated emojis will not be correct. This will not be changed as stated here: <https://github.com/discord/discord-api-docs/issues/1614#issuecomment-628548913> """ id: snowflakes.Snowflake = attr.field(hash=True, repr=True) """The ID of this entity.""" name: str = attr.field(eq=False, hash=False, repr=True) """The name of the emoji.""" is_animated: bool = attr.field(eq=False, hash=False, repr=True) """Whether the emoji is animated.""" def __str__(self) -> str: return self.mention @property def filename(self) -> str: return str(self.id) + (".gif" if self.is_animated else ".png") @property @typing.final def url_name(self) -> str: return f"{self.name}:{self.id}" @property @typing.final def mention(self) -> str: return f"<{'a' if self.is_animated else ''}:{self.url_name}>" @property @typing.final def url(self) -> str: ext = "gif" if self.is_animated else "png" return routes.CDN_CUSTOM_EMOJI.compile(urls.CDN_URL, emoji_id=self.id, file_format=ext) @classmethod def parse(cls, string: str, /) -> CustomEmoji: """Parse a given emoji mention string into a custom emoji object. Parameters ---------- string : str The emoji mention to parse. Returns ------- CustomEmoji The parsed emoji object. Raises ------ ValueError If a mention is given that has an invalid format. """ if emoji_match := _CUSTOM_EMOJI_REGEX.match(string): return CustomEmoji( id=snowflakes.Snowflake(emoji_match.group("id")), name=emoji_match.group("name"), is_animated=emoji_match.group("flags").lower() == "a", ) raise ValueError("Expected an emoji mention") @attr.define(hash=True, kw_only=True, weakref_slot=False) class KnownCustomEmoji(CustomEmoji): """Represents an emoji that is known from a guild the bot is in. This is a specialization of `CustomEmoji` that is from a guild that you _are_ part of. As a result, it contains a lot more information with it. """ app: traits.RESTAware = attr.field( repr=False, eq=False, hash=False, metadata={attr_extensions.SKIP_DEEP_COPY: True} ) """The client application that models may use for procedures.""" guild_id: snowflakes.Snowflake = attr.field(eq=False, hash=False, repr=False) """The ID of the guild this emoji belongs to.""" role_ids: typing.Sequence[snowflakes.Snowflake] = attr.field(eq=False, hash=False, repr=False) """The IDs of the roles that are whitelisted to use this emoji. If this is empty then any user can use this emoji regardless of their roles. """ user: typing.Optional[users.User] = attr.field(eq=False, hash=False, repr=False) """The user that created the emoji. .. note:: This will be `None` if you are missing the `MANAGE_EMOJIS_AND_STICKERS` permission in the server the emoji is from. """ is_colons_required: bool = attr.field(eq=False, hash=False, repr=False) """Whether this emoji must be wrapped in colons.""" is_managed: bool = attr.field(eq=False, hash=False, repr=False) """Whether the emoji is managed by an integration.""" is_available: bool = attr.field(eq=False, hash=False, repr=False) """Whether this emoji can currently be used. May be `False` due to a loss of Sever Boosts on the emoji's guild. """
View Source
@attr_extensions.with_copy @attr.define(hash=True, kw_only=True, weakref_slot=False) class CustomEmoji(snowflakes.Unique, Emoji): """Represents a custom emoji. This is a custom emoji that is from a guild you might not be part of. All CustomEmoji objects and their derivatives act as valid `hikari.files.Resource` objects. This means you can use them as a file when sending a message. >>> emojis = await bot.rest.fetch_guild_emojis(12345) >>> picks = random.choices(emojis, 5) >>> await event.respond(files=picks) .. warning:: Discord will not provide information on whether these emojis are animated or not when a reaction is removed and an event is fired. This is problematic if you need to try and determine the emoji that was removed. The side effect of this means that mentions for animated emojis will not be correct. This will not be changed as stated here: <https://github.com/discord/discord-api-docs/issues/1614#issuecomment-628548913> """ id: snowflakes.Snowflake = attr.field(hash=True, repr=True) """The ID of this entity.""" name: str = attr.field(eq=False, hash=False, repr=True) """The name of the emoji.""" is_animated: bool = attr.field(eq=False, hash=False, repr=True) """Whether the emoji is animated.""" def __str__(self) -> str: return self.mention @property def filename(self) -> str: return str(self.id) + (".gif" if self.is_animated else ".png") @property @typing.final def url_name(self) -> str: return f"{self.name}:{self.id}" @property @typing.final def mention(self) -> str: return f"<{'a' if self.is_animated else ''}:{self.url_name}>" @property @typing.final def url(self) -> str: ext = "gif" if self.is_animated else "png" return routes.CDN_CUSTOM_EMOJI.compile(urls.CDN_URL, emoji_id=self.id, file_format=ext) @classmethod def parse(cls, string: str, /) -> CustomEmoji: """Parse a given emoji mention string into a custom emoji object. Parameters ---------- string : str The emoji mention to parse. Returns ------- CustomEmoji The parsed emoji object. Raises ------ ValueError If a mention is given that has an invalid format. """ if emoji_match := _CUSTOM_EMOJI_REGEX.match(string): return CustomEmoji( id=snowflakes.Snowflake(emoji_match.group("id")), name=emoji_match.group("name"), is_animated=emoji_match.group("flags").lower() == "a", ) raise ValueError("Expected an emoji mention")
Represents a custom emoji.
This is a custom emoji that is from a guild you might not be part of.
All CustomEmoji objects and their derivatives act as valid hikari.files.Resource
objects. This means you can use them as a file when sending a message.
>>> emojis = await bot.rest.fetch_guild_emojis(12345)
>>> picks = random.choices(emojis, 5)
>>> await event.respond(files=picks)
Warning: Discord will not provide information on whether these emojis are animated or not when a reaction is removed and an event is fired. This is problematic if you need to try and determine the emoji that was removed. The side effect of this means that mentions for animated emojis will not be correct.
This will not be changed as stated here: https://github.com/discord/discord-api-docs/issues/1614#issuecomment-628548913
Variables and properties
When the object was created.
File extension, if there is one.
Filename of the resource.
The ID of this entity.
Whether the emoji is animated.
Mention string to use to mention the emoji with.
The name of the emoji.
URL of the emoji image to display in clients.
Name of the part of the emoji to use in requests.
Methods
View Source
def __init__(self, *, id, name, is_animated): self.id = id self.name = name self.is_animated = is_animated
Method generated by attrs for class CustomEmoji.
View Source
@classmethod def parse(cls, string: str, /) -> CustomEmoji: """Parse a given emoji mention string into a custom emoji object. Parameters ---------- string : str The emoji mention to parse. Returns ------- CustomEmoji The parsed emoji object. Raises ------ ValueError If a mention is given that has an invalid format. """ if emoji_match := _CUSTOM_EMOJI_REGEX.match(string): return CustomEmoji( id=snowflakes.Snowflake(emoji_match.group("id")), name=emoji_match.group("name"), is_animated=emoji_match.group("flags").lower() == "a", ) raise ValueError("Expected an emoji mention")
Parse a given emoji mention string into a custom emoji object.
Parameters
- string (str): The emoji mention to parse.
Returns
- CustomEmoji: The parsed emoji object.
Raises
- ValueError: If a mention is given that has an invalid format.
View Source
async def read( self, *, executor: typing.Optional[concurrent.futures.Executor] = None, ) -> bytes: """Read the entire resource at once into memory. ```py data = await resource.read(...) # ^-- This is a shortcut for the following --v async with resource.stream(...) as reader: data = await reader.read() ``` .. warning:: If you simply wish to re-upload this resource to Discord via any endpoint in Hikari, you should opt to just pass this resource object directly. This way, Hikari can perform byte inception, which significantly reduces the memory usage for your bot as it grows larger. Parameters ---------- executor : typing.Optional[concurrent.futures.Executor] The executor to run in for blocking operations. If `None`, then the default executor is used for the current event loop. Returns ------- bytes The entire resource. """ async with self.stream(executor=executor) as reader: return await reader.read()
Read the entire resource at once into memory.
data = await resource.read(...)
# ^-- This is a shortcut for the following --v
async with resource.stream(...) as reader:
data = await reader.read()
Warning: If you simply wish to re-upload this resource to Discord via any endpoint in Hikari, you should opt to just pass this resource object directly. This way, Hikari can perform byte inception, which significantly reduces the memory usage for your bot as it grows larger.
Parameters
- executor (typing.Optional[concurrent.futures.Executor]): The executor to run in for blocking operations. If
None
, then the default executor is used for the current event loop.
Returns
- bytes: The entire resource.
self,
*,
executor: Optional[concurrent.futures._base.Executor] = None,
head_only: bool = False
) -> hikari.files.AsyncReaderContextManager[hikari.files.WebReader]:
View Source
def stream( self, *, executor: typing.Optional[concurrent.futures.Executor] = None, head_only: bool = False, ) -> AsyncReaderContextManager[WebReader]: """Start streaming the content into memory by downloading it. You can use this to fetch the entire resource, parts of the resource, or just to view any metadata that may be provided. Parameters ---------- executor : typing.Optional[concurrent.futures.Executor] Not used. Provided only to match the underlying interface. head_only : bool Defaults to `False`. If `True`, then the implementation may only retrieve HEAD information if supported. This currently only has any effect for web requests. Examples -------- Downloading an entire resource at once into memory: ```py async with obj.stream() as stream: data = await stream.read() ``` Checking the metadata: ```py async with obj.stream() as stream: mimetype = stream.mimetype if mimetype is None: ... elif mimetype not in whitelisted_mimetypes: ... else: ... ``` Fetching the data-uri of a resource: ```py async with obj.stream() as stream: data_uri = await stream.data_uri() ``` Returns ------- AsyncReaderContextManager[WebReader] An async context manager that when entered, produces the data stream. Raises ------ hikari.errors.BadRequestError If a 400 is returned. hikari.errors.UnauthorizedError If a 401 is returned. hikari.errors.ForbiddenError If a 403 is returned. hikari.errors.NotFoundError If a 404 is returned. hikari.errors.ClientHTTPResponseError If any other 4xx is returned. hikari.errors.InternalServerError If any other 5xx is returned. hikari.errors.HTTPResponseError If any other unexpected response code is returned. """ return _WebReaderAsyncReaderContextManagerImpl(self, head_only)
Start streaming the content into memory by downloading it.
You can use this to fetch the entire resource, parts of the resource, or just to view any metadata that may be provided.
Parameters
- executor (typing.Optional[concurrent.futures.Executor]): Not used. Provided only to match the underlying interface.
- head_only (bool): Defaults to
False
. IfTrue
, then the implementation may only retrieve HEAD information if supported. This currently only has any effect for web requests.
Examples
Downloading an entire resource at once into memory:
async with obj.stream() as stream:
data = await stream.read()
Checking the metadata:
async with obj.stream() as stream:
mimetype = stream.mimetype
if mimetype is None:
...
elif mimetype not in whitelisted_mimetypes:
...
else:
...
Fetching the data-uri of a resource:
async with obj.stream() as stream:
data_uri = await stream.data_uri()
Returns
- AsyncReaderContextManager[WebReader]: An async context manager that when entered, produces the data stream.
Raises
- hikari.errors.BadRequestError: If a 400 is returned.
- hikari.errors.UnauthorizedError: If a 401 is returned.
- hikari.errors.ForbiddenError: If a 403 is returned.
- hikari.errors.NotFoundError: If a 404 is returned.
- hikari.errors.ClientHTTPResponseError: If any other 4xx is returned.
- hikari.errors.InternalServerError: If any other 5xx is returned.
- hikari.errors.HTTPResponseError: If any other unexpected response code is returned.
View Source
class Emoji(files.WebResource, abc.ABC): """Base class for all emojis. Any emoji implementation supports being used as a `hikari.files.Resource` when uploading an attachment to the API. This is achieved in the same way as using a `hikari.files.WebResource` would achieve this. """ __slots__: typing.Sequence[str] = () @property @abc.abstractmethod def name(self) -> str: """Return the generic name/representation for this emoji.""" @property @abc.abstractmethod def url(self) -> str: """URL of the emoji image to display in clients.""" @property @abc.abstractmethod def url_name(self) -> str: """Name of the part of the emoji to use in requests.""" @property @abc.abstractmethod def mention(self) -> str: """Mention string to use to mention the emoji with.""" @classmethod def parse(cls, string: str, /) -> Emoji: """Parse a given string into an emoji object. Parameters ---------- string : str The emoji object to parse. Returns ------- Emoji The parsed emoji object. This will be a `CustomEmoji` if a custom emoji mention, or a `UnicodeEmoji` otherwise. Raises ------ ValueError If a mention is given that has an invalid format. """ if string.startswith("<") and string.endswith(">"): return CustomEmoji.parse(string) return UnicodeEmoji.parse(string)
Base class for all emojis.
Any emoji implementation supports being used as a hikari.files.Resource
when uploading an attachment to the API. This is achieved in the same way as using a hikari.files.WebResource
would achieve this.
Variables and properties
File extension, if there is one.
Filename of the resource.
Mention string to use to mention the emoji with.
Return the generic name/representation for this emoji.
URL of the emoji image to display in clients.
Name of the part of the emoji to use in requests.
Methods
View Source
@classmethod def parse(cls, string: str, /) -> Emoji: """Parse a given string into an emoji object. Parameters ---------- string : str The emoji object to parse. Returns ------- Emoji The parsed emoji object. This will be a `CustomEmoji` if a custom emoji mention, or a `UnicodeEmoji` otherwise. Raises ------ ValueError If a mention is given that has an invalid format. """ if string.startswith("<") and string.endswith(">"): return CustomEmoji.parse(string) return UnicodeEmoji.parse(string)
Parse a given string into an emoji object.
Parameters
- string (str): The emoji object to parse.
Returns
- Emoji: The parsed emoji object. This will be a
CustomEmoji
if a custom emoji mention, or aUnicodeEmoji
otherwise.
Raises
- ValueError: If a mention is given that has an invalid format.
View Source
async def read( self, *, executor: typing.Optional[concurrent.futures.Executor] = None, ) -> bytes: """Read the entire resource at once into memory. ```py data = await resource.read(...) # ^-- This is a shortcut for the following --v async with resource.stream(...) as reader: data = await reader.read() ``` .. warning:: If you simply wish to re-upload this resource to Discord via any endpoint in Hikari, you should opt to just pass this resource object directly. This way, Hikari can perform byte inception, which significantly reduces the memory usage for your bot as it grows larger. Parameters ---------- executor : typing.Optional[concurrent.futures.Executor] The executor to run in for blocking operations. If `None`, then the default executor is used for the current event loop. Returns ------- bytes The entire resource. """ async with self.stream(executor=executor) as reader: return await reader.read()
Read the entire resource at once into memory.
data = await resource.read(...)
# ^-- This is a shortcut for the following --v
async with resource.stream(...) as reader:
data = await reader.read()
Warning: If you simply wish to re-upload this resource to Discord via any endpoint in Hikari, you should opt to just pass this resource object directly. This way, Hikari can perform byte inception, which significantly reduces the memory usage for your bot as it grows larger.
Parameters
- executor (typing.Optional[concurrent.futures.Executor]): The executor to run in for blocking operations. If
None
, then the default executor is used for the current event loop.
Returns
- bytes: The entire resource.
self,
*,
executor: Optional[concurrent.futures._base.Executor] = None,
head_only: bool = False
) -> hikari.files.AsyncReaderContextManager[hikari.files.WebReader]:
View Source
def stream( self, *, executor: typing.Optional[concurrent.futures.Executor] = None, head_only: bool = False, ) -> AsyncReaderContextManager[WebReader]: """Start streaming the content into memory by downloading it. You can use this to fetch the entire resource, parts of the resource, or just to view any metadata that may be provided. Parameters ---------- executor : typing.Optional[concurrent.futures.Executor] Not used. Provided only to match the underlying interface. head_only : bool Defaults to `False`. If `True`, then the implementation may only retrieve HEAD information if supported. This currently only has any effect for web requests. Examples -------- Downloading an entire resource at once into memory: ```py async with obj.stream() as stream: data = await stream.read() ``` Checking the metadata: ```py async with obj.stream() as stream: mimetype = stream.mimetype if mimetype is None: ... elif mimetype not in whitelisted_mimetypes: ... else: ... ``` Fetching the data-uri of a resource: ```py async with obj.stream() as stream: data_uri = await stream.data_uri() ``` Returns ------- AsyncReaderContextManager[WebReader] An async context manager that when entered, produces the data stream. Raises ------ hikari.errors.BadRequestError If a 400 is returned. hikari.errors.UnauthorizedError If a 401 is returned. hikari.errors.ForbiddenError If a 403 is returned. hikari.errors.NotFoundError If a 404 is returned. hikari.errors.ClientHTTPResponseError If any other 4xx is returned. hikari.errors.InternalServerError If any other 5xx is returned. hikari.errors.HTTPResponseError If any other unexpected response code is returned. """ return _WebReaderAsyncReaderContextManagerImpl(self, head_only)
Start streaming the content into memory by downloading it.
You can use this to fetch the entire resource, parts of the resource, or just to view any metadata that may be provided.
Parameters
- executor (typing.Optional[concurrent.futures.Executor]): Not used. Provided only to match the underlying interface.
- head_only (bool): Defaults to
False
. IfTrue
, then the implementation may only retrieve HEAD information if supported. This currently only has any effect for web requests.
Examples
Downloading an entire resource at once into memory:
async with obj.stream() as stream:
data = await stream.read()
Checking the metadata:
async with obj.stream() as stream:
mimetype = stream.mimetype
if mimetype is None:
...
elif mimetype not in whitelisted_mimetypes:
...
else:
...
Fetching the data-uri of a resource:
async with obj.stream() as stream:
data_uri = await stream.data_uri()
Returns
- AsyncReaderContextManager[WebReader]: An async context manager that when entered, produces the data stream.
Raises
- hikari.errors.BadRequestError: If a 400 is returned.
- hikari.errors.UnauthorizedError: If a 401 is returned.
- hikari.errors.ForbiddenError: If a 403 is returned.
- hikari.errors.NotFoundError: If a 404 is returned.
- hikari.errors.ClientHTTPResponseError: If any other 4xx is returned.
- hikari.errors.InternalServerError: If any other 5xx is returned.
- hikari.errors.HTTPResponseError: If any other unexpected response code is returned.
View Source
@attr.define(hash=True, kw_only=True, weakref_slot=False) class KnownCustomEmoji(CustomEmoji): """Represents an emoji that is known from a guild the bot is in. This is a specialization of `CustomEmoji` that is from a guild that you _are_ part of. As a result, it contains a lot more information with it. """ app: traits.RESTAware = attr.field( repr=False, eq=False, hash=False, metadata={attr_extensions.SKIP_DEEP_COPY: True} ) """The client application that models may use for procedures.""" guild_id: snowflakes.Snowflake = attr.field(eq=False, hash=False, repr=False) """The ID of the guild this emoji belongs to.""" role_ids: typing.Sequence[snowflakes.Snowflake] = attr.field(eq=False, hash=False, repr=False) """The IDs of the roles that are whitelisted to use this emoji. If this is empty then any user can use this emoji regardless of their roles. """ user: typing.Optional[users.User] = attr.field(eq=False, hash=False, repr=False) """The user that created the emoji. .. note:: This will be `None` if you are missing the `MANAGE_EMOJIS_AND_STICKERS` permission in the server the emoji is from. """ is_colons_required: bool = attr.field(eq=False, hash=False, repr=False) """Whether this emoji must be wrapped in colons.""" is_managed: bool = attr.field(eq=False, hash=False, repr=False) """Whether the emoji is managed by an integration.""" is_available: bool = attr.field(eq=False, hash=False, repr=False) """Whether this emoji can currently be used. May be `False` due to a loss of Sever Boosts on the emoji's guild. """
Represents an emoji that is known from a guild the bot is in.
This is a specialization of CustomEmoji
that is from a guild that you _are_ part of. As a result, it contains a lot more information with it.
Variables and properties
The client application that models may use for procedures.
When the object was created.
File extension, if there is one.
Filename of the resource.
The ID of the guild this emoji belongs to.
The ID of this entity.
Whether the emoji is animated.
Whether this emoji can currently be used.
May be False
due to a loss of Sever Boosts on the emoji's guild.
Whether this emoji must be wrapped in colons.
Whether the emoji is managed by an integration.
Mention string to use to mention the emoji with.
The name of the emoji.
The IDs of the roles that are whitelisted to use this emoji.
If this is empty then any user can use this emoji regardless of their roles.
URL of the emoji image to display in clients.
Name of the part of the emoji to use in requests.
The user that created the emoji.
Note: This will be None
if you are missing the MANAGE_EMOJIS_AND_STICKERS
permission in the server the emoji is from.
Methods
self,
*,
id: hikari.snowflakes.Snowflake,
name: str,
is_animated: bool,
app: hikari.traits.RESTAware,
guild_id: hikari.snowflakes.Snowflake,
role_ids: Sequence[hikari.snowflakes.Snowflake],
user: Optional[hikari.users.User],
is_colons_required: bool,
is_managed: bool,
is_available: bool
):
View Source
def __init__(self, *, id, name, is_animated, app, guild_id, role_ids, user, is_colons_required, is_managed, is_available): self.id = id self.name = name self.is_animated = is_animated self.app = app self.guild_id = guild_id self.role_ids = role_ids self.user = user self.is_colons_required = is_colons_required self.is_managed = is_managed self.is_available = is_available
Method generated by attrs for class KnownCustomEmoji.
View Source
@classmethod def parse(cls, string: str, /) -> CustomEmoji: """Parse a given emoji mention string into a custom emoji object. Parameters ---------- string : str The emoji mention to parse. Returns ------- CustomEmoji The parsed emoji object. Raises ------ ValueError If a mention is given that has an invalid format. """ if emoji_match := _CUSTOM_EMOJI_REGEX.match(string): return CustomEmoji( id=snowflakes.Snowflake(emoji_match.group("id")), name=emoji_match.group("name"), is_animated=emoji_match.group("flags").lower() == "a", ) raise ValueError("Expected an emoji mention")
Parse a given emoji mention string into a custom emoji object.
Parameters
- string (str): The emoji mention to parse.
Returns
- CustomEmoji: The parsed emoji object.
Raises
- ValueError: If a mention is given that has an invalid format.
View Source
async def read( self, *, executor: typing.Optional[concurrent.futures.Executor] = None, ) -> bytes: """Read the entire resource at once into memory. ```py data = await resource.read(...) # ^-- This is a shortcut for the following --v async with resource.stream(...) as reader: data = await reader.read() ``` .. warning:: If you simply wish to re-upload this resource to Discord via any endpoint in Hikari, you should opt to just pass this resource object directly. This way, Hikari can perform byte inception, which significantly reduces the memory usage for your bot as it grows larger. Parameters ---------- executor : typing.Optional[concurrent.futures.Executor] The executor to run in for blocking operations. If `None`, then the default executor is used for the current event loop. Returns ------- bytes The entire resource. """ async with self.stream(executor=executor) as reader: return await reader.read()
Read the entire resource at once into memory.
data = await resource.read(...)
# ^-- This is a shortcut for the following --v
async with resource.stream(...) as reader:
data = await reader.read()
Warning: If you simply wish to re-upload this resource to Discord via any endpoint in Hikari, you should opt to just pass this resource object directly. This way, Hikari can perform byte inception, which significantly reduces the memory usage for your bot as it grows larger.
Parameters
- executor (typing.Optional[concurrent.futures.Executor]): The executor to run in for blocking operations. If
None
, then the default executor is used for the current event loop.
Returns
- bytes: The entire resource.
self,
*,
executor: Optional[concurrent.futures._base.Executor] = None,
head_only: bool = False
) -> hikari.files.AsyncReaderContextManager[hikari.files.WebReader]:
View Source
def stream( self, *, executor: typing.Optional[concurrent.futures.Executor] = None, head_only: bool = False, ) -> AsyncReaderContextManager[WebReader]: """Start streaming the content into memory by downloading it. You can use this to fetch the entire resource, parts of the resource, or just to view any metadata that may be provided. Parameters ---------- executor : typing.Optional[concurrent.futures.Executor] Not used. Provided only to match the underlying interface. head_only : bool Defaults to `False`. If `True`, then the implementation may only retrieve HEAD information if supported. This currently only has any effect for web requests. Examples -------- Downloading an entire resource at once into memory: ```py async with obj.stream() as stream: data = await stream.read() ``` Checking the metadata: ```py async with obj.stream() as stream: mimetype = stream.mimetype if mimetype is None: ... elif mimetype not in whitelisted_mimetypes: ... else: ... ``` Fetching the data-uri of a resource: ```py async with obj.stream() as stream: data_uri = await stream.data_uri() ``` Returns ------- AsyncReaderContextManager[WebReader] An async context manager that when entered, produces the data stream. Raises ------ hikari.errors.BadRequestError If a 400 is returned. hikari.errors.UnauthorizedError If a 401 is returned. hikari.errors.ForbiddenError If a 403 is returned. hikari.errors.NotFoundError If a 404 is returned. hikari.errors.ClientHTTPResponseError If any other 4xx is returned. hikari.errors.InternalServerError If any other 5xx is returned. hikari.errors.HTTPResponseError If any other unexpected response code is returned. """ return _WebReaderAsyncReaderContextManagerImpl(self, head_only)
Start streaming the content into memory by downloading it.
You can use this to fetch the entire resource, parts of the resource, or just to view any metadata that may be provided.
Parameters
- executor (typing.Optional[concurrent.futures.Executor]): Not used. Provided only to match the underlying interface.
- head_only (bool): Defaults to
False
. IfTrue
, then the implementation may only retrieve HEAD information if supported. This currently only has any effect for web requests.
Examples
Downloading an entire resource at once into memory:
async with obj.stream() as stream:
data = await stream.read()
Checking the metadata:
async with obj.stream() as stream:
mimetype = stream.mimetype
if mimetype is None:
...
elif mimetype not in whitelisted_mimetypes:
...
else:
...
Fetching the data-uri of a resource:
async with obj.stream() as stream:
data_uri = await stream.data_uri()
Returns
- AsyncReaderContextManager[WebReader]: An async context manager that when entered, produces the data stream.
Raises
- hikari.errors.BadRequestError: If a 400 is returned.
- hikari.errors.UnauthorizedError: If a 401 is returned.
- hikari.errors.ForbiddenError: If a 403 is returned.
- hikari.errors.NotFoundError: If a 404 is returned.
- hikari.errors.ClientHTTPResponseError: If any other 4xx is returned.
- hikari.errors.InternalServerError: If any other 5xx is returned.
- hikari.errors.HTTPResponseError: If any other unexpected response code is returned.
View Source
class UnicodeEmoji(str, Emoji): """Represents a unicode emoji. .. warning:: A word of warning if you try to upload this emoji as a file attachment. While this emoji type can be used to upload the Twemoji representations of this emoji as a PNG, this is NOT foolproof. The mapping between Discord's implementation and official Twemoji bindings is very flaky. Responsible implementations relying on this behaviour will be implemented to expect this behaviour in the form of `hikari.errors.NotFoundError` exceptions being raised when a mismatch may occur. It is also likely that this will change in the future without notice, so you will likely be relying on flaky behaviour. If this is proven to be too unstable, this functionality will be removed in a future release after a deprecation period. """ __slots__: typing.Sequence[str] = () @property def name(self) -> str: """Return the code points which form the emoji.""" return self @property @typing.final def url_name(self) -> str: return self @property def mention(self) -> str: return self @property @typing.final def codepoints(self) -> typing.Sequence[int]: """Integer codepoints that make up this emoji, as UTF-8.""" return [ord(c) for c in self] @property def filename(self) -> str: """Filename to use if re-uploading this emoji's PNG.""" codepoints = self.codepoints # It looks like the rule is to delete character #2 if the value # of this is 0xfe0f and the character is up to 4 characters long. # Other than that, the mapping is 1-to-1. There's a couple of outliers # to this 0xfe0f rule and they seem to follow a pattern where the # codepoint after 0xfe0f is 0x200D but this might be a coincidence and # if Discord start breaking this regularly I might need to ask for a # more permanent solution. This is provisionally provided. If we find it # breaks in other ways, I will just revoke this functionality in a # future update. if codepoints[1:2] == [0xFE0F] and len(codepoints) <= 4 and codepoints[2:3] != [0x200D]: codepoints = [codepoints[0], *codepoints[2:]] return "-".join(hex(c)[2:] for c in codepoints) + ".png" @property def url(self) -> str: """Get the URL of the PNG rendition of this emoji. This will use the official Twitter "twemoji" repository to fetch this information, as Discord only stores this in a hashed format that uses SVG files, which is not usually of any use. Since this uses "twemoji" directly, the emojis may not directly match what is on Discord if Discord have failed to keep their emoji packs up-to-date with this repository. Example ------- ```py >>> emoji = hikari.UnicodeEmoji("\N{OK HAND SIGN}") >>> emoji.url 'https://raw.githubusercontent.com/twitter/twemoji/master/assets/72x72/1f44c.png' ``` """ return _TWEMOJI_PNG_BASE_URL + self.filename # @property # @typing.final # def unicode_names(self) -> typing.Sequence[str]: # """Get the unicode name of the emoji as a sequence. # # This returns the name of each codepoint. If only one codepoint exists, # then this will only have one item in the resulting sequence. # """ # return [unicodedata.name(c) for c in self] @property @typing.final def unicode_escape(self) -> str: """Get the unicode escape string for this emoji.""" return bytes(self, "unicode_escape").decode("utf-8") @classmethod @typing.final def parse_codepoints(cls, codepoint: int, *codepoints: int) -> UnicodeEmoji: """Create a unicode emoji from one or more UTF-32 codepoints.""" return cls("".join(map(chr, (codepoint, *codepoints)))) @classmethod @typing.final def parse_unicode_escape(cls, escape: str) -> UnicodeEmoji: """Create a unicode emoji from a unicode escape string.""" return cls(escape.encode("utf-8"), "unicode_escape") @classmethod @typing.final def parse(cls, string: str, /) -> UnicodeEmoji: """Parse a given string into a unicode emoji object. Parameters ---------- string : str The emoji object to parse. Returns ------- UnicodeEmoji The parsed UnicodeEmoji object. """ # TODO: Re-add validity # Ensure validity. # for i, codepoint in enumerate(string, start=1): # unicodedata.name(codepoint) return cls(string)
Represents a unicode emoji.
Warning: A word of warning if you try to upload this emoji as a file attachment.
While this emoji type can be used to upload the Twemoji representations of this emoji as a PNG, this is NOT foolproof. The mapping between Discord's implementation and official Twemoji bindings is very flaky. Responsible implementations relying on this behaviour will be implemented to expect this behaviour in the form of hikari.errors.NotFoundError
exceptions being raised when a mismatch may occur. It is also likely that this will change in the future without notice, so you will likely be relying on flaky behaviour.
If this is proven to be too unstable, this functionality will be removed in a future release after a deprecation period.
Variables and properties
Integer codepoints that make up this emoji, as UTF-8.
File extension, if there is one.
Filename to use if re-uploading this emoji's PNG.
Mention string to use to mention the emoji with.
Return the code points which form the emoji.
Get the unicode escape string for this emoji.
Get the URL of the PNG rendition of this emoji.
This will use the official Twitter "twemoji" repository to fetch this information, as Discord only stores this in a hashed format that uses SVG files, which is not usually of any use.
Since this uses "twemoji" directly, the emojis may not directly match what is on Discord if Discord have failed to keep their emoji packs up-to-date with this repository.
Example
>>> emoji = hikari.UnicodeEmoji("👌")
>>> emoji.url
'https://raw.githubusercontent.com/twitter/twemoji/master/assets/72x72/1f44c.png'
Name of the part of the emoji to use in requests.
Methods
Return a capitalized version of the string.
More specifically, make the first character have upper case and the rest lower case.
Return a version of the string suitable for caseless comparisons.
Return a centered string of length width.
Padding is done using the specified fill character (default is a space).
S.count(sub[, start[, end]]) -> int
Return the number of non-overlapping occurrences of substring sub in string S[start:end]. Optional arguments start and end are interpreted as in slice notation.
Encode the string using the codec registered for encoding.
encoding The encoding in which to encode the string. errors The error handling scheme to use for encoding errors. The default is 'strict' meaning that encoding errors raise a UnicodeEncodeError. Other possible values are 'ignore', 'replace' and 'xmlcharrefreplace' as well as any other name registered with codecs.register_error that can handle UnicodeEncodeErrors.
S.endswith(suffix[, start[, end]]) -> bool
Return True if S ends with the specified suffix, False otherwise. With optional start, test S beginning at that position. With optional end, stop comparing S at that position. suffix can also be a tuple of strings to try.
Return a copy where all tab characters are expanded using spaces.
If tabsize is not given, a tab size of 8 characters is assumed.
S.find(sub[, start[, end]]) -> int
Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.
Return -1 on failure.
S.format(args, *kwargs) -> str
Return a formatted version of S, using substitutions from args and kwargs. The substitutions are identified by braces ('{' and '}').
S.format_map(mapping) -> str
Return a formatted version of S, using substitutions from mapping. The substitutions are identified by braces ('{' and '}').
S.index(sub[, start[, end]]) -> int
Return the lowest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.
Raises ValueError when the substring is not found.
Return True if the string is an alpha-numeric string, False otherwise.
A string is alpha-numeric if all characters in the string are alpha-numeric and there is at least one character in the string.
Return True if the string is an alphabetic string, False otherwise.
A string is alphabetic if all characters in the string are alphabetic and there is at least one character in the string.
Return True if all characters in the string are ASCII, False otherwise.
ASCII characters have code points in the range U+0000-U+007F. Empty string is ASCII too.
Return True if the string is a decimal string, False otherwise.
A string is a decimal string if all characters in the string are decimal and there is at least one character in the string.
Return True if the string is a digit string, False otherwise.
A string is a digit string if all characters in the string are digits and there is at least one character in the string.
Return True if the string is a valid Python identifier, False otherwise.
Call keyword.iskeyword(s) to test whether string s is a reserved identifier, such as "def" or "class".
Return True if the string is a lowercase string, False otherwise.
A string is lowercase if all cased characters in the string are lowercase and there is at least one cased character in the string.
Return True if the string is a numeric string, False otherwise.
A string is numeric if all characters in the string are numeric and there is at least one character in the string.
Return True if the string is printable, False otherwise.
A string is printable if all of its characters are considered printable in repr() or if it is empty.
Return True if the string is a whitespace string, False otherwise.
A string is whitespace if all characters in the string are whitespace and there is at least one character in the string.
Return True if the string is a title-cased string, False otherwise.
In a title-cased string, upper- and title-case characters may only follow uncased characters and lowercase characters only cased ones.
Return True if the string is an uppercase string, False otherwise.
A string is uppercase if all cased characters in the string are uppercase and there is at least one cased character in the string.
Concatenate any number of strings.
The string whose method is called is inserted in between each given string. The result is returned as a new string.
Example: '.'.join(['ab', 'pq', 'rs']) -> 'ab.pq.rs'
Return a left-justified string of length width.
Padding is done using the specified fill character (default is a space).
Return a copy of the string converted to lowercase.
Return a copy of the string with leading whitespace removed.
If chars is given and not None, remove characters in chars instead.
Return a translation table usable for str.translate().
If there is only one argument, it must be a dictionary mapping Unicode ordinals (integers) or characters to Unicode ordinals, strings or None. Character keys will be then converted to ordinals. If there are two arguments, they must be strings of equal length, and in the resulting dictionary, each character in x will be mapped to the character at the same position in y. If there is a third argument, it must be a string, whose characters will be mapped to None in the result.
View Source
@classmethod @typing.final def parse(cls, string: str, /) -> UnicodeEmoji: """Parse a given string into a unicode emoji object. Parameters ---------- string : str The emoji object to parse. Returns ------- UnicodeEmoji The parsed UnicodeEmoji object. """ # TODO: Re-add validity # Ensure validity. # for i, codepoint in enumerate(string, start=1): # unicodedata.name(codepoint) return cls(string)
Parse a given string into a unicode emoji object.
Parameters
- string (str): The emoji object to parse.
Returns
- UnicodeEmoji: The parsed UnicodeEmoji object.
View Source
@classmethod @typing.final def parse_codepoints(cls, codepoint: int, *codepoints: int) -> UnicodeEmoji: """Create a unicode emoji from one or more UTF-32 codepoints.""" return cls("".join(map(chr, (codepoint, *codepoints))))
Create a unicode emoji from one or more UTF-32 codepoints.
View Source
@classmethod @typing.final def parse_unicode_escape(cls, escape: str) -> UnicodeEmoji: """Create a unicode emoji from a unicode escape string.""" return cls(escape.encode("utf-8"), "unicode_escape")
Create a unicode emoji from a unicode escape string.
Partition the string into three parts using the given separator.
This will search for the separator in the string. If the separator is found, returns a 3-tuple containing the part before the separator, the separator itself, and the part after it.
If the separator is not found, returns a 3-tuple containing the original string and two empty strings.
View Source
async def read( self, *, executor: typing.Optional[concurrent.futures.Executor] = None, ) -> bytes: """Read the entire resource at once into memory. ```py data = await resource.read(...) # ^-- This is a shortcut for the following --v async with resource.stream(...) as reader: data = await reader.read() ``` .. warning:: If you simply wish to re-upload this resource to Discord via any endpoint in Hikari, you should opt to just pass this resource object directly. This way, Hikari can perform byte inception, which significantly reduces the memory usage for your bot as it grows larger. Parameters ---------- executor : typing.Optional[concurrent.futures.Executor] The executor to run in for blocking operations. If `None`, then the default executor is used for the current event loop. Returns ------- bytes The entire resource. """ async with self.stream(executor=executor) as reader: return await reader.read()
Read the entire resource at once into memory.
data = await resource.read(...)
# ^-- This is a shortcut for the following --v
async with resource.stream(...) as reader:
data = await reader.read()
Warning: If you simply wish to re-upload this resource to Discord via any endpoint in Hikari, you should opt to just pass this resource object directly. This way, Hikari can perform byte inception, which significantly reduces the memory usage for your bot as it grows larger.
Parameters
- executor (typing.Optional[concurrent.futures.Executor]): The executor to run in for blocking operations. If
None
, then the default executor is used for the current event loop.
Returns
- bytes: The entire resource.
Return a str with the given prefix string removed if present.
If the string starts with the prefix string, return string[len(prefix):]. Otherwise, return a copy of the original string.
Return a str with the given suffix string removed if present.
If the string ends with the suffix string and that suffix is not empty, return string[:-len(suffix)]. Otherwise, return a copy of the original string.
Return a copy with all occurrences of substring old replaced by new.
count Maximum number of occurrences to replace. -1 (the default value) means replace all occurrences.
If the optional argument count is given, only the first count occurrences are replaced.
S.rfind(sub[, start[, end]]) -> int
Return the highest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.
Return -1 on failure.
S.rindex(sub[, start[, end]]) -> int
Return the highest index in S where substring sub is found, such that sub is contained within S[start:end]. Optional arguments start and end are interpreted as in slice notation.
Raises ValueError when the substring is not found.
Return a right-justified string of length width.
Padding is done using the specified fill character (default is a space).
Partition the string into three parts using the given separator.
This will search for the separator in the string, starting at the end. If the separator is found, returns a 3-tuple containing the part before the separator, the separator itself, and the part after it.
If the separator is not found, returns a 3-tuple containing two empty strings and the original string.
Return a list of the words in the string, using sep as the delimiter string.
sep The delimiter according which to split the string. None (the default value) means split according to any whitespace, and discard empty strings from the result. maxsplit Maximum number of splits to do. -1 (the default value) means no limit.
Splits are done starting at the end of the string and working to the front.
Return a copy of the string with trailing whitespace removed.
If chars is given and not None, remove characters in chars instead.
Return a list of the words in the string, using sep as the delimiter string.
sep The delimiter according which to split the string. None (the default value) means split according to any whitespace, and discard empty strings from the result. maxsplit Maximum number of splits to do. -1 (the default value) means no limit.
Return a list of the lines in the string, breaking at line boundaries.
Line breaks are not included in the resulting list unless keepends is given and true.
S.startswith(prefix[, start[, end]]) -> bool
Return True if S starts with the specified prefix, False otherwise. With optional start, test S beginning at that position. With optional end, stop comparing S at that position. prefix can also be a tuple of strings to try.
self,
*,
executor: Optional[concurrent.futures._base.Executor] = None,
head_only: bool = False
) -> hikari.files.AsyncReaderContextManager[hikari.files.WebReader]:
View Source
def stream( self, *, executor: typing.Optional[concurrent.futures.Executor] = None, head_only: bool = False, ) -> AsyncReaderContextManager[WebReader]: """Start streaming the content into memory by downloading it. You can use this to fetch the entire resource, parts of the resource, or just to view any metadata that may be provided. Parameters ---------- executor : typing.Optional[concurrent.futures.Executor] Not used. Provided only to match the underlying interface. head_only : bool Defaults to `False`. If `True`, then the implementation may only retrieve HEAD information if supported. This currently only has any effect for web requests. Examples -------- Downloading an entire resource at once into memory: ```py async with obj.stream() as stream: data = await stream.read() ``` Checking the metadata: ```py async with obj.stream() as stream: mimetype = stream.mimetype if mimetype is None: ... elif mimetype not in whitelisted_mimetypes: ... else: ... ``` Fetching the data-uri of a resource: ```py async with obj.stream() as stream: data_uri = await stream.data_uri() ``` Returns ------- AsyncReaderContextManager[WebReader] An async context manager that when entered, produces the data stream. Raises ------ hikari.errors.BadRequestError If a 400 is returned. hikari.errors.UnauthorizedError If a 401 is returned. hikari.errors.ForbiddenError If a 403 is returned. hikari.errors.NotFoundError If a 404 is returned. hikari.errors.ClientHTTPResponseError If any other 4xx is returned. hikari.errors.InternalServerError If any other 5xx is returned. hikari.errors.HTTPResponseError If any other unexpected response code is returned. """ return _WebReaderAsyncReaderContextManagerImpl(self, head_only)
Start streaming the content into memory by downloading it.
You can use this to fetch the entire resource, parts of the resource, or just to view any metadata that may be provided.
Parameters
- executor (typing.Optional[concurrent.futures.Executor]): Not used. Provided only to match the underlying interface.
- head_only (bool): Defaults to
False
. IfTrue
, then the implementation may only retrieve HEAD information if supported. This currently only has any effect for web requests.
Examples
Downloading an entire resource at once into memory:
async with obj.stream() as stream:
data = await stream.read()
Checking the metadata:
async with obj.stream() as stream:
mimetype = stream.mimetype
if mimetype is None:
...
elif mimetype not in whitelisted_mimetypes:
...
else:
...
Fetching the data-uri of a resource:
async with obj.stream() as stream:
data_uri = await stream.data_uri()
Returns
- AsyncReaderContextManager[WebReader]: An async context manager that when entered, produces the data stream.
Raises
- hikari.errors.BadRequestError: If a 400 is returned.
- hikari.errors.UnauthorizedError: If a 401 is returned.
- hikari.errors.ForbiddenError: If a 403 is returned.
- hikari.errors.NotFoundError: If a 404 is returned.
- hikari.errors.ClientHTTPResponseError: If any other 4xx is returned.
- hikari.errors.InternalServerError: If any other 5xx is returned.
- hikari.errors.HTTPResponseError: If any other unexpected response code is returned.
Return a copy of the string with leading and trailing whitespace removed.
If chars is given and not None, remove characters in chars instead.
Convert uppercase characters to lowercase and lowercase characters to uppercase.
Return a version of the string where each word is titlecased.
More specifically, words start with uppercased characters and all remaining cased characters have lower case.
Replace each character in the string using the given translation table.
table Translation table, which must be a mapping of Unicode ordinals to Unicode ordinals, strings, or None.
The table must implement lookup/indexing via __getitem__, for instance a dictionary or list. If this operation raises LookupError, the character is left untouched. Characters mapped to None are deleted.
Return a copy of the string converted to uppercase.
Pad a numeric string with zeros on the left, to fill a field of the given width.
The string is never truncated.