Back to top

hikari.users

Application and entities that are used to describe Users 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 Users on Discord."""

from __future__ import annotations

__all__: typing.Sequence[str] = ("PartialUser", "User", "OwnUser", "UserFlag", "PremiumType")

import abc
import typing

import attr

from hikari import snowflakes
from hikari import traits
from hikari import undefined
from hikari import urls
from hikari.internal import attr_extensions
from hikari.internal import enums
from hikari.internal import routes

if typing.TYPE_CHECKING:
    from hikari import channels
    from hikari import colors
    from hikari import embeds as embeds_
    from hikari import files
    from hikari import guilds
    from hikari import locales
    from hikari import messages
    from hikari.api import special_endpoints


@typing.final
class UserFlag(enums.Flag):
    """The known user flags that represent account badges."""

    NONE = 0
    """None"""

    DISCORD_EMPLOYEE = 1 << 0
    """Discord Employee."""

    PARTNERED_SERVER_OWNER = 1 << 1
    """Owner of a partnered Discord server."""

    HYPESQUAD_EVENTS = 1 << 2
    """HypeSquad Events."""

    BUG_HUNTER_LEVEL_1 = 1 << 3
    """Bug Hunter Level 1."""

    HYPESQUAD_BRAVERY = 1 << 6
    """House of Bravery."""

    HYPESQUAD_BRILLIANCE = 1 << 7
    """House of Brilliance."""

    HYPESQUAD_BALANCE = 1 << 8
    """House of Balance."""

    EARLY_SUPPORTER = 1 << 9
    """Early Supporter."""

    TEAM_USER = 1 << 10
    """Team user."""

    BUG_HUNTER_LEVEL_2 = 1 << 14
    """Bug Hunter Level 2."""

    VERIFIED_BOT = 1 << 16
    """Verified Bot."""

    EARLY_VERIFIED_DEVELOPER = 1 << 17
    """Early verified Bot Developer.

    Only applies to users that verified their account before 20th August 2019.
    """

    DISCORD_CERTIFIED_MODERATOR = 1 << 18
    """Discord Certified Moderator."""

    BOT_HTTP_INTERACTIONS = 1 << 19
    """Bot uses only HTTP interactions and is shown in the active member list."""


@typing.final
class PremiumType(int, enums.Enum):
    """The types of Nitro."""

    NONE = 0
    """No premium."""

    NITRO_CLASSIC = 1
    """Premium including basic perks like animated emojis and avatars."""

    NITRO = 2
    """Premium including all perks (e.g. 2 server boosts)."""


class PartialUser(snowflakes.Unique, abc.ABC):
    """A partial interface for a user.

    Fields may or may not be present, and should be explicitly checked
    before using them to ensure they are not `hikari.undefined.UNDEFINED`.

    This is used for endpoints and events that only expose partial user
    information.

    For full user info, consider calling the `fetch_self` method to perform an
    API call.
    """

    __slots__: typing.Sequence[str] = ()

    @property
    @abc.abstractmethod
    def app(self) -> traits.RESTAware:
        """Client application that models may use for procedures."""

    @property
    @abc.abstractmethod
    def avatar_hash(self) -> undefined.UndefinedNoneOr[str]:
        """Avatar hash for the user, if they have one, otherwise `None`."""

    @property
    @abc.abstractmethod
    def banner_hash(self) -> undefined.UndefinedNoneOr[str]:
        """Banner hash for the user, if they have one, otherwise `hikari.undefined.UNDEFINED`."""

    @property
    @abc.abstractmethod
    def accent_color(self) -> undefined.UndefinedNoneOr[colors.Color]:
        """Custom banner color for the user if set, else `None`.

        Will be `hikari.undefined.UNDEFINED` if not known.

        The official client will decide the default color if not set.
        """  # noqa: D401 - Imperative mood

    @property
    def accent_colour(self) -> undefined.UndefinedNoneOr[colors.Color]:
        """Alias for the `accent_color` field."""
        return self.accent_color

    @property
    @abc.abstractmethod
    def discriminator(self) -> undefined.UndefinedOr[str]:
        """Discriminator for the user."""

    @property
    @abc.abstractmethod
    def username(self) -> undefined.UndefinedOr[str]:
        """Username for the user."""

    @property
    @abc.abstractmethod
    def is_bot(self) -> undefined.UndefinedOr[bool]:
        """Whether this user is a bot account."""

    @property
    @abc.abstractmethod
    def is_system(self) -> undefined.UndefinedOr[bool]:
        """`Whether  this user is a system account."""

    @property
    @abc.abstractmethod
    def flags(self) -> undefined.UndefinedOr[UserFlag]:
        """Flag bits that are set for the user."""

    @property
    @abc.abstractmethod
    def mention(self) -> str:
        """Return a raw mention string for the given user.

        Example
        -------
        ```py
        >>> some_user.mention
        '<@123456789123456789>'
        ```
        """

    async def fetch_dm_channel(self) -> channels.DMChannel:
        """Fetch the DM channel for this user.

        Returns
        -------
        hikari.channels.DMChannel
            The requested channel.

        Raises
        ------
        hikari.errors.UnauthorizedError
            If you are unauthorized to make the request (invalid/missing token).
        hikari.errors.NotFoundError
            If the user is not found.
        hikari.errors.RateLimitTooLongError
            Raised in the event that a rate limit occurs that is
            longer than `max_rate_limit` when making a request.
        hikari.errors.RateLimitedError
            Usually, Hikari will handle and retry on hitting
            rate-limits automatically. This includes most bucket-specific
            rate-limits and global rate-limits. In some rare edge cases,
            however, Discord implements other undocumented rules for
            rate-limiting, such as limits per attribute. These cannot be
            detected or handled normally by Hikari due to their undocumented
            nature, and will trigger this exception if they occur.
        hikari.errors.InternalServerError
            If an internal error occurs on Discord while handling the request.
        """
        return await self.app.rest.create_dm_channel(self.id)

    async def fetch_self(self) -> User:
        """Get this user's up-to-date object by performing an API call.

        Returns
        -------
        hikari.users.User
            The requested user object.

        Raises
        ------
        hikari.errors.NotFoundError
            If the user is not found.
        hikari.errors.RateLimitTooLongError
            Raised in the event that a rate limit occurs that is
            longer than `max_rate_limit` when making a request.
        hikari.errors.RateLimitedError
            Usually, Hikari will handle and retry on hitting
            rate-limits automatically. This includes most bucket-specific
            rate-limits and global rate-limits. In some rare edge cases,
            however, Discord implements other undocumented rules for
            rate-limiting, such as limits per attribute. These cannot be
            detected or handled normally by Hikari due to their undocumented
            nature, and will trigger this exception if they occur.
        hikari.errors.InternalServerError
            If an internal error occurs on Discord while handling the request.
        """
        return await self.app.rest.fetch_user(user=self.id)

    async def send(
        self,
        content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
        *,
        attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
        attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
        component: undefined.UndefinedOr[special_endpoints.ComponentBuilder] = undefined.UNDEFINED,
        components: undefined.UndefinedOr[typing.Sequence[special_endpoints.ComponentBuilder]] = undefined.UNDEFINED,
        embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
        embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
        tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        reply: undefined.UndefinedOr[snowflakes.SnowflakeishOr[messages.PartialMessage]] = undefined.UNDEFINED,
        mentions_everyone: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        mentions_reply: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        user_mentions: undefined.UndefinedOr[
            typing.Union[snowflakes.SnowflakeishSequence[PartialUser], bool]
        ] = undefined.UNDEFINED,
        role_mentions: undefined.UndefinedOr[
            typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]
        ] = undefined.UNDEFINED,
    ) -> messages.Message:
        """Send a message to this user in DM's.

        Parameters
        ----------
        content : hikari.undefined.UndefinedOr[typing.Any]
            If provided, the message contents. If
            `hikari.undefined.UNDEFINED`, then nothing will be sent
            in the content. Any other value here will be cast to a
            `str`.

            If this is a `hikari.embeds.Embed` and no `embed` nor `embeds` kwarg
            is provided, then this will instead update the embed. This allows
            for simpler syntax when sending an embed alone.

            Likewise, if this is a `hikari.files.Resource`, then the
            content is instead treated as an attachment if no `attachment` and
            no `attachments` kwargs are provided.


        Other Parameters
        ----------------
        attachment : hikari.undefined.UndefinedOr[hikari.files.Resourceish],
            If provided, the message attachment. This can be a resource,
            or string of a path on your computer or a URL.

            Attachments can be passed as many different things, to aid in
            convenience.

            - If a `pathlib.PurePath` or `str` to a valid URL, the
                resource at the given URL will be streamed to Discord when
                sending the message. Subclasses of
                `hikari.files.WebResource` such as
                `hikari.files.URL`,
                `hikari.messages.Attachment`,
                `hikari.emojis.Emoji`,
                `EmbedResource`, etc will also be uploaded this way.
                This will use bit-inception, so only a small percentage of the
                resource will remain in memory at any one time, thus aiding in
                scalability.
            - If a `hikari.files.Bytes` is passed, or a `str`
                that contains a valid data URI is passed, then this is uploaded
                with a randomized file name if not provided.
            - If a `hikari.files.File`, `pathlib.PurePath` or
                `str` that is an absolute or relative path to a file
                on your file system is passed, then this resource is uploaded
                as an attachment using non-blocking code internally and streamed
                using bit-inception where possible. This depends on the
                type of `concurrent.futures.Executor` that is being used for
                the application (default is a thread pool which supports this
                behaviour).
        attachments : hikari.undefined.UndefinedOr[typing.Sequence[hikari.files.Resourceish]],
            If provided, the message attachments. These can be resources, or
            strings consisting of paths on your computer or URLs.
        component : hikari.undefined.UndefinedOr[hikari.api.special_endpoints.ComponentBuilder]
            If provided, builder object of the component to include in this message.
        components : hikari.undefined.UndefinedOr[typing.Sequence[hikari.api.special_endpoints.ComponentBuilder]]
            If provided, a sequence of the component builder objects to include
            in this message.
        embed : hikari.undefined.UndefinedOr[hikari.embeds.Embed]
            If provided, the message embed.
        embeds : hikari.undefined.UndefinedOr[typing.Sequence[hikari.embeds.Embed]]
            If provided, the message embeds.
        tts : hikari.undefined.UndefinedOr[bool]
            If provided, whether the message will be read out by a screen
            reader using Discord's TTS (text-to-speech) system.
        reply : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.messages.PartialMessage]]
            If provided, the message to reply to.
        mentions_everyone : hikari.undefined.UndefinedOr[bool]
            If provided, whether the message should parse @everyone/@here
            mentions.
        mentions_reply : hikari.undefined.UndefinedOr[bool]
            If provided, whether to mention the author of the message
            that is being replied to.

            This will not do anything if not being used with `reply`.
        user_mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.users.PartialUser], bool]]
            If provided, and `True`, all user mentions will be detected.
            If provided, and `False`, all user mentions will be ignored
            if appearing in the message body.
            Alternatively this may be a collection of
            `hikari.snowflakes.Snowflake`, or
            `hikari.users.PartialUser` derivatives to enforce mentioning
            specific users.
        role_mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.guilds.PartialRole], bool]]
            If provided, and `True`, all role mentions will be detected.
            If provided, and `False`, all role mentions will be ignored
            if appearing in the message body.
            Alternatively this may be a collection of
            `hikari.snowflakes.Snowflake`, or
            `hikari.guilds.PartialRole` derivatives to enforce mentioning
            specific roles.

        Returns
        -------
        hikari.messages.Message
            The created message.

        Raises
        ------
        ValueError
            If more than 100 unique objects/entities are passed for
            `role_mentions` or `user_mentions`.
        TypeError
            If both `attachment` and `attachments` are specified.
        hikari.errors.BadRequestError
            This may be raised in several discrete situations, such as messages
            being empty with no attachments or embeds; messages with more than
            2000 characters in them, embeds that exceed one of the many embed
            limits; too many attachments; attachments that are too large;
            invalid image URLs in embeds; `reply` not found or not in the same
            channel; too many components.
        hikari.errors.UnauthorizedError
            If you are unauthorized to make the request (invalid/missing token).
        hikari.errors.ForbiddenError
            If you are missing the `SEND_MESSAGES` in the channel or the
            person you are trying to message has the DM's disabled.
        hikari.errors.NotFoundError
            If the user is not found.
        hikari.errors.RateLimitTooLongError
            Raised in the event that a rate limit occurs that is
            longer than `max_rate_limit` when making a request.
        hikari.errors.RateLimitedError
            Usually, Hikari will handle and retry on hitting
            rate-limits automatically. This includes most bucket-specific
            rate-limits and global rate-limits. In some rare edge cases,
            however, Discord implements other undocumented rules for
            rate-limiting, such as limits per attribute. These cannot be
            detected or handled normally by Hikari due to their undocumented
            nature, and will trigger this exception if they occur.
        hikari.errors.InternalServerError
            If an internal error occurs on Discord while handling the request.
        """  # noqa: E501 - Line too long
        channel_id = None
        if isinstance(self.app, traits.CacheAware):
            channel_id = self.app.cache.get_dm_channel_id(self.id)

        if channel_id is None:
            channel_id = (await self.fetch_dm_channel()).id

        return await self.app.rest.create_message(
            channel=channel_id,
            content=content,
            attachment=attachment,
            attachments=attachments,
            component=component,
            components=components,
            embed=embed,
            embeds=embeds,
            tts=tts,
            reply=reply,
            mentions_everyone=mentions_everyone,
            user_mentions=user_mentions,
            role_mentions=role_mentions,
            mentions_reply=mentions_reply,
        )


class User(PartialUser, abc.ABC):
    """Interface for any user-like object.

    This does not include partial users, as they may not be fully formed.
    """

    __slots__: typing.Sequence[str] = ()

    @property
    @abc.abstractmethod
    def app(self) -> traits.RESTAware:
        """Client application that models may use for procedures."""

    @property
    @abc.abstractmethod
    def accent_color(self) -> typing.Optional[colors.Color]:
        """The custom banner color for the user, if set else `None`.

        The official client will decide the default color if not set.
        """  # noqa: D401 - Imperative mood

    @property
    def accent_colour(self) -> typing.Optional[colors.Color]:
        """Alias for the `accent_color` field."""
        return self.accent_color

    @property
    @abc.abstractmethod
    def avatar_hash(self) -> typing.Optional[str]:
        """Avatar hash for the user, if they have one, otherwise `None`."""

    @property
    def avatar_url(self) -> typing.Optional[files.URL]:
        """Avatar URL for the user, if they have one set.

        May be `None` if no custom avatar is set. In this case, you
        should use `default_avatar_url` instead.
        """
        return self.make_avatar_url()

    @property
    @abc.abstractmethod
    def banner_hash(self) -> typing.Optional[str]:
        """Banner hash for the user, if they have one, otherwise `hikari.undefined.UNDEFINED`."""

    @property
    def banner_url(self) -> typing.Optional[files.URL]:
        """Banner URL for the user, if they have one set.

        May be `None` if no custom banner is set.
        """
        return self.make_banner_url()

    @property
    def default_avatar_url(self) -> files.URL:
        """Default avatar URL for this user."""  # noqa: D401 - Imperative mood
        return routes.CDN_DEFAULT_USER_AVATAR.compile_to_file(
            urls.CDN_URL,
            discriminator=int(self.discriminator) % 5,
            file_format="png",
        )

    @property
    def display_avatar_url(self) -> files.URL:
        """Display avatar URL for this user."""
        return self.make_avatar_url() or self.default_avatar_url

    @property
    @abc.abstractmethod
    def discriminator(self) -> str:
        """Discriminator for the user."""

    @property
    @abc.abstractmethod
    def flags(self) -> UserFlag:
        """Flag bits that are set for the user."""

    @property
    @abc.abstractmethod
    def is_bot(self) -> bool:
        """Whether this user is a bot account."""

    @property
    @abc.abstractmethod
    def is_system(self) -> bool:
        """Whether this user is a system account."""

    @property
    @abc.abstractmethod
    def mention(self) -> str:
        """Return a raw mention string for the given user.

        Example
        -------
        ```py
        >>> some_user.mention
        '<@123456789123456789>'
        ```
        """

    @property
    @abc.abstractmethod
    def username(self) -> str:
        """Username for the user."""

    def make_avatar_url(self, *, ext: typing.Optional[str] = None, size: int = 4096) -> typing.Optional[files.URL]:
        """Generate the avatar URL for this user, if set.

        If no custom avatar is set, this returns `None`. You can then
        use the `default_avatar_url` attribute instead to fetch the displayed
        URL.

        Parameters
        ----------
        ext : typing.Optional[str]
            The ext to use for this URL, defaults to `png` or `gif`.
            Supports `png`, `jpeg`, `jpg`, `webp` and `gif` (when
            animated). Will be ignored for default avatars which can only be
            `png`.

            If `None`, then the correct default extension is
            determined based on whether the icon is animated or not.
        size : int
            The size to set for the URL, defaults to `4096`.
            Can be any power of two between 16 and 4096.
            Will be ignored for default avatars.

        Returns
        -------
        typing.Optional[hikari.files.URL]
            The URL to the avatar, or `None` if not present.

        Raises
        ------
        ValueError
            If `size` is not a power of two or not between 16 and 4096.
        """
        if self.avatar_hash is None:
            return None

        if ext is None:
            if self.avatar_hash.startswith("a_"):
                ext = "gif"
            else:
                ext = "png"

        return routes.CDN_USER_AVATAR.compile_to_file(
            urls.CDN_URL,
            user_id=self.id,
            hash=self.avatar_hash,
            size=size,
            file_format=ext,
        )

    def make_banner_url(self, *, ext: typing.Optional[str] = None, size: int = 4096) -> typing.Optional[files.URL]:
        """Generate the banner URL for this user, if set.

        If no custom banner is set, this returns `None`.

        Parameters
        ----------
        ext : typing.Optional[str]
            The ext to use for this URL, defaults to `png` or `gif`.
            Supports `png`, `jpeg`, `jpg`, `webp` and `gif` (when
            animated).

            If `None`, then the correct default extension is
            determined based on whether the banner is animated or not.
        size : int
            The size to set for the URL, defaults to `4096`.
            Can be any power of two between 16 and 4096.

        Returns
        -------
        typing.Optional[hikari.files.URL]
            The URL to the banner, or `None` if not present.

        Raises
        ------
        ValueError
            If `size` is not a power of two or not between 16 and 4096.
        """
        if self.banner_hash is None:
            return None

        if ext is None:
            if self.banner_hash.startswith("a_"):
                ext = "gif"
            else:
                ext = "png"

        return routes.CDN_USER_BANNER.compile_to_file(
            urls.CDN_URL,
            user_id=self.id,
            hash=self.banner_hash,
            size=size,
            file_format=ext,
        )


@attr_extensions.with_copy
@attr.define(hash=True, kw_only=True, weakref_slot=False)
class PartialUserImpl(PartialUser):
    """Implementation for partial information about a user.

    This is pretty much the same as a normal user, but information may not be
    present.
    """

    id: snowflakes.Snowflake = attr.field(hash=True, repr=True)
    """The ID of this user."""

    app: traits.RESTAware = attr.field(
        repr=False, eq=False, hash=False, metadata={attr_extensions.SKIP_DEEP_COPY: True}
    )
    """Reference to the client application that models may use for procedures."""

    discriminator: undefined.UndefinedOr[str] = attr.field(eq=False, hash=False, repr=True)
    """Four-digit discriminator for the user."""

    username: undefined.UndefinedOr[str] = attr.field(eq=False, hash=False, repr=True)
    """Username of the user."""

    avatar_hash: undefined.UndefinedNoneOr[str] = attr.field(eq=False, hash=False, repr=False)
    """Avatar hash of the user, if a custom avatar is set."""

    banner_hash: undefined.UndefinedNoneOr[str] = attr.field(eq=False, hash=False, repr=False)
    """Banner hash of the user, if a custom banner is set."""

    accent_color: undefined.UndefinedNoneOr[colors.Color] = attr.field(eq=False, hash=False, repr=False)
    """The custom banner color for the user, if set.

    The official client will decide the default color if not set.
    """

    is_bot: undefined.UndefinedOr[bool] = attr.field(eq=False, hash=False, repr=True)
    """Whether this user is a bot account."""

    is_system: undefined.UndefinedOr[bool] = attr.field(eq=False, hash=False, repr=True)
    """Whether this user is a system account."""

    flags: undefined.UndefinedOr[UserFlag] = attr.field(eq=False, hash=False, repr=True)
    """Public flags for this user."""

    @property
    def mention(self) -> str:
        """Return a raw mention string for the given user.

        Example
        -------

        ```py
        >>> some_user.mention
        '<@123456789123456789>'
        ```
        """
        return f"<@{self.id}>"

    def __str__(self) -> str:
        if self.username is undefined.UNDEFINED or self.discriminator is undefined.UNDEFINED:
            return f"Partial user ID {self.id}"
        return f"{self.username}#{self.discriminator}"


@attr.define(hash=True, kw_only=True, weakref_slot=False)
class UserImpl(PartialUserImpl, User):
    """Concrete implementation of user information."""

    discriminator: str = attr.field(eq=False, hash=False, repr=True)
    """The user's discriminator."""

    username: str = attr.field(eq=False, hash=False, repr=True)
    """The user's username."""

    avatar_hash: typing.Optional[str] = attr.field(eq=False, hash=False, repr=False)
    """The user's avatar hash, if they have one, otherwise `None`."""

    banner_hash: typing.Optional[str] = attr.field(eq=False, hash=False, repr=False)
    """Banner hash of the user, if they have one, otherwise `None`"""

    accent_color: typing.Optional[colors.Color] = attr.field(eq=False, hash=False, repr=False)
    """The custom banner color for the user, if set.

    The official client will decide the default color if not set.
    """  # noqa: D401 - Imperative mood

    is_bot: bool = attr.field(eq=False, hash=False, repr=True)
    """`True` if this user is a bot account, `False` otherwise."""

    is_system: bool = attr.field(eq=False, hash=False, repr=True)
    """`True` if this user is a system account, `False` otherwise."""

    flags: UserFlag = attr.field(eq=False, hash=False, repr=True)
    """The public flags for this user."""


@attr.define(hash=True, kw_only=True, weakref_slot=False)
class OwnUser(UserImpl):
    """Represents a user with extended OAuth2 information."""

    is_mfa_enabled: bool = attr.field(eq=False, hash=False, repr=False)
    """Whether the user's account has multi-factor authentication enabled."""

    locale: typing.Optional[typing.Union[str, locales.Locale]] = attr.field(eq=False, hash=False, repr=False)
    """The user's set locale.

    This is not provided in the `READY` event.
    """

    is_verified: typing.Optional[bool] = attr.field(eq=False, hash=False, repr=False)
    """Whether the email for this user's account has been verified.

    Will be `None` if retrieved through the OAuth2 flow without the `email`
    scope.
    """

    email: typing.Optional[str] = attr.field(eq=False, hash=False, repr=False)
    """The user's set email.

    Will be `None` if retrieved through OAuth2 flow without the `email`
    scope. Will always be `None` for bot users.
    """

    premium_type: typing.Union[PremiumType, int, None] = attr.field(eq=False, hash=False, repr=False)
    """The type of Nitro Subscription this user account had.

    This will always be `None` for bots.
    """

    async def fetch_self(self) -> OwnUser:
        """Get this user's up-to-date object.

        Returns
        -------
        hikari.users.OwnUser
            The requested user object.

        Raises
        ------
        hikari.errors.UnauthorizedError
            If you are unauthorized to make the request (invalid/missing token).
        hikari.errors.RateLimitTooLongError
            Raised in the event that a rate limit occurs that is
            longer than `max_rate_limit` when making a request.
        hikari.errors.RateLimitedError
            Usually, Hikari will handle and retry on hitting
            rate-limits automatically. This includes most bucket-specific
            rate-limits and global rate-limits. In some rare edge cases,
            however, Discord implements other undocumented rules for
            rate-limiting, such as limits per attribute. These cannot be
            detected or handled normally by Hikari due to their undocumented
            nature, and will trigger this exception if they occur.
        hikari.errors.InternalServerError
            If an internal error occurs on Discord while handling the request.
        """
        return await self.app.rest.fetch_my_user()

    async def fetch_dm_channel(self) -> typing.NoReturn:
        raise TypeError("Unable to fetch your own DM channel")

    async def send(
        self,
        content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
        *,
        attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
        attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
        component: undefined.UndefinedOr[special_endpoints.ComponentBuilder] = undefined.UNDEFINED,
        components: undefined.UndefinedOr[typing.Sequence[special_endpoints.ComponentBuilder]] = undefined.UNDEFINED,
        embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
        embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
        nonce: undefined.UndefinedOr[str] = undefined.UNDEFINED,
        tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        reply: undefined.UndefinedOr[snowflakes.SnowflakeishOr[messages.PartialMessage]] = undefined.UNDEFINED,
        mentions_everyone: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        mentions_reply: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        user_mentions: undefined.UndefinedOr[
            typing.Union[snowflakes.SnowflakeishSequence[PartialUser], bool]
        ] = undefined.UNDEFINED,
        role_mentions: undefined.UndefinedOr[
            typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]
        ] = undefined.UNDEFINED,
    ) -> typing.NoReturn:
        raise TypeError("Unable to send a DM to yourself")
#  
@attr.define(hash=True, kw_only=True, weakref_slot=False)
class OwnUser(UserImpl):
View Source
@attr.define(hash=True, kw_only=True, weakref_slot=False)
class OwnUser(UserImpl):
    """Represents a user with extended OAuth2 information."""

    is_mfa_enabled: bool = attr.field(eq=False, hash=False, repr=False)
    """Whether the user's account has multi-factor authentication enabled."""

    locale: typing.Optional[typing.Union[str, locales.Locale]] = attr.field(eq=False, hash=False, repr=False)
    """The user's set locale.

    This is not provided in the `READY` event.
    """

    is_verified: typing.Optional[bool] = attr.field(eq=False, hash=False, repr=False)
    """Whether the email for this user's account has been verified.

    Will be `None` if retrieved through the OAuth2 flow without the `email`
    scope.
    """

    email: typing.Optional[str] = attr.field(eq=False, hash=False, repr=False)
    """The user's set email.

    Will be `None` if retrieved through OAuth2 flow without the `email`
    scope. Will always be `None` for bot users.
    """

    premium_type: typing.Union[PremiumType, int, None] = attr.field(eq=False, hash=False, repr=False)
    """The type of Nitro Subscription this user account had.

    This will always be `None` for bots.
    """

    async def fetch_self(self) -> OwnUser:
        """Get this user's up-to-date object.

        Returns
        -------
        hikari.users.OwnUser
            The requested user object.

        Raises
        ------
        hikari.errors.UnauthorizedError
            If you are unauthorized to make the request (invalid/missing token).
        hikari.errors.RateLimitTooLongError
            Raised in the event that a rate limit occurs that is
            longer than `max_rate_limit` when making a request.
        hikari.errors.RateLimitedError
            Usually, Hikari will handle and retry on hitting
            rate-limits automatically. This includes most bucket-specific
            rate-limits and global rate-limits. In some rare edge cases,
            however, Discord implements other undocumented rules for
            rate-limiting, such as limits per attribute. These cannot be
            detected or handled normally by Hikari due to their undocumented
            nature, and will trigger this exception if they occur.
        hikari.errors.InternalServerError
            If an internal error occurs on Discord while handling the request.
        """
        return await self.app.rest.fetch_my_user()

    async def fetch_dm_channel(self) -> typing.NoReturn:
        raise TypeError("Unable to fetch your own DM channel")

    async def send(
        self,
        content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
        *,
        attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
        attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
        component: undefined.UndefinedOr[special_endpoints.ComponentBuilder] = undefined.UNDEFINED,
        components: undefined.UndefinedOr[typing.Sequence[special_endpoints.ComponentBuilder]] = undefined.UNDEFINED,
        embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
        embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
        nonce: undefined.UndefinedOr[str] = undefined.UNDEFINED,
        tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        reply: undefined.UndefinedOr[snowflakes.SnowflakeishOr[messages.PartialMessage]] = undefined.UNDEFINED,
        mentions_everyone: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        mentions_reply: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        user_mentions: undefined.UndefinedOr[
            typing.Union[snowflakes.SnowflakeishSequence[PartialUser], bool]
        ] = undefined.UNDEFINED,
        role_mentions: undefined.UndefinedOr[
            typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]
        ] = undefined.UNDEFINED,
    ) -> typing.NoReturn:
        raise TypeError("Unable to send a DM to yourself")

Represents a user with extended OAuth2 information.

Variables and properties
#  accent_color: Optional[hikari.colors.Color]

The custom banner color for the user, if set.

The official client will decide the default color if not set.

#  accent_colour: Optional[hikari.colors.Color]

Alias for the accent_color field.

Reference to the client application that models may use for procedures.

#  avatar_hash: Optional[str]

The user's avatar hash, if they have one, otherwise None.

#  avatar_url: Optional[hikari.files.URL]

Avatar URL for the user, if they have one set.

May be None if no custom avatar is set. In this case, you should use default_avatar_url instead.

#  banner_hash: Optional[str]

Banner hash of the user, if they have one, otherwise None

#  banner_url: Optional[hikari.files.URL]

Banner URL for the user, if they have one set.

May be None if no custom banner is set.

#  created_at: datetime.datetime

When the object was created.

#  default_avatar_url: hikari.files.URL

Default avatar URL for this user.

#  discriminator: str

The user's discriminator.

#  display_avatar_url: hikari.files.URL

Display avatar URL for this user.

#  email: Optional[str]

The user's set email.

Will be None if retrieved through OAuth2 flow without the email scope. Will always be None for bot users.

The public flags for this user.

The ID of this user.

#  is_bot: bool

True if this user is a bot account, False otherwise.

#  is_mfa_enabled: bool

Whether the user's account has multi-factor authentication enabled.

#  is_system: bool

True if this user is a system account, False otherwise.

#  is_verified: Optional[bool]

Whether the email for this user's account has been verified.

Will be None if retrieved through the OAuth2 flow without the email scope.

#  locale: Union[str, hikari.locales.Locale, NoneType]

The user's set locale.

This is not provided in the READY event.

#  mention: str

Return a raw mention string for the given user.

Example
>>> some_user.mention
'<@123456789123456789>'
#  premium_type: Union[hikari.users.PremiumType, int, NoneType]

The type of Nitro Subscription this user account had.

This will always be None for bots.

#  username: str

The user's username.

Methods
#  def __init__(
   self,
   *,
   id: hikari.snowflakes.Snowflake,
   app: hikari.traits.RESTAware,
   discriminator: str,
   username: str,
   avatar_hash: Optional[str],
   banner_hash: Optional[str],
   accent_color: Optional[hikari.colors.Color],
   is_bot: bool,
   is_system: bool,
   flags: hikari.users.UserFlag,
   is_mfa_enabled: bool,
   locale: Union[str, hikari.locales.Locale, NoneType],
   is_verified: Optional[bool],
   email: Optional[str],
   premium_type: Union[hikari.users.PremiumType, int, NoneType]
):
View Source
def __init__(self, *, id, app, discriminator, username, avatar_hash, banner_hash, accent_color, is_bot, is_system, flags, is_mfa_enabled, locale, is_verified, email, premium_type):
    self.id = id
    self.app = app
    self.discriminator = discriminator
    self.username = username
    self.avatar_hash = avatar_hash
    self.banner_hash = banner_hash
    self.accent_color = accent_color
    self.is_bot = is_bot
    self.is_system = is_system
    self.flags = flags
    self.is_mfa_enabled = is_mfa_enabled
    self.locale = locale
    self.is_verified = is_verified
    self.email = email
    self.premium_type = premium_type

Method generated by attrs for class OwnUser.

#  async def fetch_dm_channel(self) -> NoReturn:
View Source
    async def fetch_dm_channel(self) -> typing.NoReturn:
        raise TypeError("Unable to fetch your own DM channel")

Fetch the DM channel for this user.

Returns
Raises
  • hikari.errors.UnauthorizedError: If you are unauthorized to make the request (invalid/missing token).
  • hikari.errors.NotFoundError: If the user is not found.
  • hikari.errors.RateLimitTooLongError: Raised in the event that a rate limit occurs that is longer than max_rate_limit when making a request.
  • hikari.errors.RateLimitedError: Usually, Hikari will handle and retry on hitting rate-limits automatically. This includes most bucket-specific rate-limits and global rate-limits. In some rare edge cases, however, Discord implements other undocumented rules for rate-limiting, such as limits per attribute. These cannot be detected or handled normally by Hikari due to their undocumented nature, and will trigger this exception if they occur.
  • hikari.errors.InternalServerError: If an internal error occurs on Discord while handling the request.
#  async def fetch_self(self) -> hikari.users.OwnUser:
View Source
    async def fetch_self(self) -> OwnUser:
        """Get this user's up-to-date object.

        Returns
        -------
        hikari.users.OwnUser
            The requested user object.

        Raises
        ------
        hikari.errors.UnauthorizedError
            If you are unauthorized to make the request (invalid/missing token).
        hikari.errors.RateLimitTooLongError
            Raised in the event that a rate limit occurs that is
            longer than `max_rate_limit` when making a request.
        hikari.errors.RateLimitedError
            Usually, Hikari will handle and retry on hitting
            rate-limits automatically. This includes most bucket-specific
            rate-limits and global rate-limits. In some rare edge cases,
            however, Discord implements other undocumented rules for
            rate-limiting, such as limits per attribute. These cannot be
            detected or handled normally by Hikari due to their undocumented
            nature, and will trigger this exception if they occur.
        hikari.errors.InternalServerError
            If an internal error occurs on Discord while handling the request.
        """
        return await self.app.rest.fetch_my_user()

Get this user's up-to-date object.

Returns
Raises
  • hikari.errors.UnauthorizedError: If you are unauthorized to make the request (invalid/missing token).
  • hikari.errors.RateLimitTooLongError: Raised in the event that a rate limit occurs that is longer than max_rate_limit when making a request.
  • hikari.errors.RateLimitedError: Usually, Hikari will handle and retry on hitting rate-limits automatically. This includes most bucket-specific rate-limits and global rate-limits. In some rare edge cases, however, Discord implements other undocumented rules for rate-limiting, such as limits per attribute. These cannot be detected or handled normally by Hikari due to their undocumented nature, and will trigger this exception if they occur.
  • hikari.errors.InternalServerError: If an internal error occurs on Discord while handling the request.
#  def make_avatar_url(
   self,
   *,
   ext: Optional[str] = None,
   size: int = 4096
) -> Optional[hikari.files.URL]:
View Source
    def make_avatar_url(self, *, ext: typing.Optional[str] = None, size: int = 4096) -> typing.Optional[files.URL]:
        """Generate the avatar URL for this user, if set.

        If no custom avatar is set, this returns `None`. You can then
        use the `default_avatar_url` attribute instead to fetch the displayed
        URL.

        Parameters
        ----------
        ext : typing.Optional[str]
            The ext to use for this URL, defaults to `png` or `gif`.
            Supports `png`, `jpeg`, `jpg`, `webp` and `gif` (when
            animated). Will be ignored for default avatars which can only be
            `png`.

            If `None`, then the correct default extension is
            determined based on whether the icon is animated or not.
        size : int
            The size to set for the URL, defaults to `4096`.
            Can be any power of two between 16 and 4096.
            Will be ignored for default avatars.

        Returns
        -------
        typing.Optional[hikari.files.URL]
            The URL to the avatar, or `None` if not present.

        Raises
        ------
        ValueError
            If `size` is not a power of two or not between 16 and 4096.
        """
        if self.avatar_hash is None:
            return None

        if ext is None:
            if self.avatar_hash.startswith("a_"):
                ext = "gif"
            else:
                ext = "png"

        return routes.CDN_USER_AVATAR.compile_to_file(
            urls.CDN_URL,
            user_id=self.id,
            hash=self.avatar_hash,
            size=size,
            file_format=ext,
        )

Generate the avatar URL for this user, if set.

If no custom avatar is set, this returns None. You can then use the default_avatar_url attribute instead to fetch the displayed URL.

Parameters
  • ext (typing.Optional[str]): The ext to use for this URL, defaults to png or gif. Supports png, jpeg, jpg, webp and gif (when animated). Will be ignored for default avatars which can only be png.

    If None, then the correct default extension is determined based on whether the icon is animated or not.

  • size (int): The size to set for the URL, defaults to 4096. Can be any power of two between 16 and 4096. Will be ignored for default avatars.
Returns
  • typing.Optional[hikari.files.URL]: The URL to the avatar, or None if not present.
Raises
  • ValueError: If size is not a power of two or not between 16 and 4096.
#  def make_banner_url(
   self,
   *,
   ext: Optional[str] = None,
   size: int = 4096
) -> Optional[hikari.files.URL]:
View Source
    def make_banner_url(self, *, ext: typing.Optional[str] = None, size: int = 4096) -> typing.Optional[files.URL]:
        """Generate the banner URL for this user, if set.

        If no custom banner is set, this returns `None`.

        Parameters
        ----------
        ext : typing.Optional[str]
            The ext to use for this URL, defaults to `png` or `gif`.
            Supports `png`, `jpeg`, `jpg`, `webp` and `gif` (when
            animated).

            If `None`, then the correct default extension is
            determined based on whether the banner is animated or not.
        size : int
            The size to set for the URL, defaults to `4096`.
            Can be any power of two between 16 and 4096.

        Returns
        -------
        typing.Optional[hikari.files.URL]
            The URL to the banner, or `None` if not present.

        Raises
        ------
        ValueError
            If `size` is not a power of two or not between 16 and 4096.
        """
        if self.banner_hash is None:
            return None

        if ext is None:
            if self.banner_hash.startswith("a_"):
                ext = "gif"
            else:
                ext = "png"

        return routes.CDN_USER_BANNER.compile_to_file(
            urls.CDN_URL,
            user_id=self.id,
            hash=self.banner_hash,
            size=size,
            file_format=ext,
        )

Generate the banner URL for this user, if set.

If no custom banner is set, this returns None.

Parameters
  • ext (typing.Optional[str]): The ext to use for this URL, defaults to png or gif. Supports png, jpeg, jpg, webp and gif (when animated).

    If None, then the correct default extension is determined based on whether the banner is animated or not.

  • size (int): The size to set for the URL, defaults to 4096. Can be any power of two between 16 and 4096.
Returns
  • typing.Optional[hikari.files.URL]: The URL to the banner, or None if not present.
Raises
  • ValueError: If size is not a power of two or not between 16 and 4096.
#  async def send(
   self,
   content: Union[Any, hikari.undefined.UndefinedType] = UNDEFINED,
   *,
   attachment: Union[hikari.files.Resource[Any], os.PathLike[str], str, bytes, bytearray, memoryview, _io.BytesIO, _io.StringIO, hikari.undefined.UndefinedType] = UNDEFINED,
   attachments: Union[Sequence[Union[hikari.files.Resource[Any], os.PathLike[str], str, bytes, bytearray, memoryview, _io.BytesIO, _io.StringIO]], hikari.undefined.UndefinedType] = UNDEFINED,
   component: Union[hikari.api.special_endpoints.ComponentBuilder, hikari.undefined.UndefinedType] = UNDEFINED,
   components: Union[Sequence[hikari.api.special_endpoints.ComponentBuilder], hikari.undefined.UndefinedType] = UNDEFINED,
   embed: Union[hikari.embeds.Embed, hikari.undefined.UndefinedType] = UNDEFINED,
   embeds: Union[Sequence[hikari.embeds.Embed], hikari.undefined.UndefinedType] = UNDEFINED,
   nonce: Union[str, hikari.undefined.UndefinedType] = UNDEFINED,
   tts: Union[bool, hikari.undefined.UndefinedType] = UNDEFINED,
   reply: Union[hikari.messages.PartialMessage, hikari.snowflakes.Snowflake, int, hikari.undefined.UndefinedType] = UNDEFINED,
   mentions_everyone: Union[bool, hikari.undefined.UndefinedType] = UNDEFINED,
   mentions_reply: Union[bool, hikari.undefined.UndefinedType] = UNDEFINED,
   user_mentions: Union[Sequence[Union[hikari.users.PartialUser, hikari.snowflakes.Snowflake, int]], bool, hikari.undefined.UndefinedType] = UNDEFINED,
   role_mentions: Union[Sequence[Union[hikari.guilds.PartialRole, hikari.snowflakes.Snowflake, int]], bool, hikari.undefined.UndefinedType] = UNDEFINED
) -> NoReturn:
View Source
    async def send(
        self,
        content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
        *,
        attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
        attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
        component: undefined.UndefinedOr[special_endpoints.ComponentBuilder] = undefined.UNDEFINED,
        components: undefined.UndefinedOr[typing.Sequence[special_endpoints.ComponentBuilder]] = undefined.UNDEFINED,
        embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
        embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
        nonce: undefined.UndefinedOr[str] = undefined.UNDEFINED,
        tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        reply: undefined.UndefinedOr[snowflakes.SnowflakeishOr[messages.PartialMessage]] = undefined.UNDEFINED,
        mentions_everyone: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        mentions_reply: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        user_mentions: undefined.UndefinedOr[
            typing.Union[snowflakes.SnowflakeishSequence[PartialUser], bool]
        ] = undefined.UNDEFINED,
        role_mentions: undefined.UndefinedOr[
            typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]
        ] = undefined.UNDEFINED,
    ) -> typing.NoReturn:
        raise TypeError("Unable to send a DM to yourself")

Send a message to this user in DM's.

Parameters
  • content (hikari.undefined.UndefinedOr[typing.Any]): If provided, the message contents. If hikari.undefined.UNDEFINED, then nothing will be sent in the content. Any other value here will be cast to a str.

    If this is a hikari.embeds.Embed and no embed nor embeds kwarg is provided, then this will instead update the embed. This allows for simpler syntax when sending an embed alone.

    Likewise, if this is a hikari.files.Resource, then the content is instead treated as an attachment if no attachment and no attachments kwargs are provided.

Other Parameters
Returns
Raises
  • ValueError: If more than 100 unique objects/entities are passed for role_mentions or user_mentions.
  • TypeError: If both attachment and attachments are specified.
  • hikari.errors.BadRequestError: This may be raised in several discrete situations, such as messages being empty with no attachments or embeds; messages with more than 2000 characters in them, embeds that exceed one of the many embed limits; too many attachments; attachments that are too large; invalid image URLs in embeds; reply not found or not in the same channel; too many components.
  • hikari.errors.UnauthorizedError: If you are unauthorized to make the request (invalid/missing token).
  • hikari.errors.ForbiddenError: If you are missing the SEND_MESSAGES in the channel or the person you are trying to message has the DM's disabled.
  • hikari.errors.NotFoundError: If the user is not found.
  • hikari.errors.RateLimitTooLongError: Raised in the event that a rate limit occurs that is longer than max_rate_limit when making a request.
  • hikari.errors.RateLimitedError: Usually, Hikari will handle and retry on hitting rate-limits automatically. This includes most bucket-specific rate-limits and global rate-limits. In some rare edge cases, however, Discord implements other undocumented rules for rate-limiting, such as limits per attribute. These cannot be detected or handled normally by Hikari due to their undocumented nature, and will trigger this exception if they occur.
  • hikari.errors.InternalServerError: If an internal error occurs on Discord while handling the request.
#  class PartialUser(hikari.snowflakes.Unique, abc.ABC):
View Source
class PartialUser(snowflakes.Unique, abc.ABC):
    """A partial interface for a user.

    Fields may or may not be present, and should be explicitly checked
    before using them to ensure they are not `hikari.undefined.UNDEFINED`.

    This is used for endpoints and events that only expose partial user
    information.

    For full user info, consider calling the `fetch_self` method to perform an
    API call.
    """

    __slots__: typing.Sequence[str] = ()

    @property
    @abc.abstractmethod
    def app(self) -> traits.RESTAware:
        """Client application that models may use for procedures."""

    @property
    @abc.abstractmethod
    def avatar_hash(self) -> undefined.UndefinedNoneOr[str]:
        """Avatar hash for the user, if they have one, otherwise `None`."""

    @property
    @abc.abstractmethod
    def banner_hash(self) -> undefined.UndefinedNoneOr[str]:
        """Banner hash for the user, if they have one, otherwise `hikari.undefined.UNDEFINED`."""

    @property
    @abc.abstractmethod
    def accent_color(self) -> undefined.UndefinedNoneOr[colors.Color]:
        """Custom banner color for the user if set, else `None`.

        Will be `hikari.undefined.UNDEFINED` if not known.

        The official client will decide the default color if not set.
        """  # noqa: D401 - Imperative mood

    @property
    def accent_colour(self) -> undefined.UndefinedNoneOr[colors.Color]:
        """Alias for the `accent_color` field."""
        return self.accent_color

    @property
    @abc.abstractmethod
    def discriminator(self) -> undefined.UndefinedOr[str]:
        """Discriminator for the user."""

    @property
    @abc.abstractmethod
    def username(self) -> undefined.UndefinedOr[str]:
        """Username for the user."""

    @property
    @abc.abstractmethod
    def is_bot(self) -> undefined.UndefinedOr[bool]:
        """Whether this user is a bot account."""

    @property
    @abc.abstractmethod
    def is_system(self) -> undefined.UndefinedOr[bool]:
        """`Whether  this user is a system account."""

    @property
    @abc.abstractmethod
    def flags(self) -> undefined.UndefinedOr[UserFlag]:
        """Flag bits that are set for the user."""

    @property
    @abc.abstractmethod
    def mention(self) -> str:
        """Return a raw mention string for the given user.

        Example
        -------
        ```py
        >>> some_user.mention
        '<@123456789123456789>'
        ```
        """

    async def fetch_dm_channel(self) -> channels.DMChannel:
        """Fetch the DM channel for this user.

        Returns
        -------
        hikari.channels.DMChannel
            The requested channel.

        Raises
        ------
        hikari.errors.UnauthorizedError
            If you are unauthorized to make the request (invalid/missing token).
        hikari.errors.NotFoundError
            If the user is not found.
        hikari.errors.RateLimitTooLongError
            Raised in the event that a rate limit occurs that is
            longer than `max_rate_limit` when making a request.
        hikari.errors.RateLimitedError
            Usually, Hikari will handle and retry on hitting
            rate-limits automatically. This includes most bucket-specific
            rate-limits and global rate-limits. In some rare edge cases,
            however, Discord implements other undocumented rules for
            rate-limiting, such as limits per attribute. These cannot be
            detected or handled normally by Hikari due to their undocumented
            nature, and will trigger this exception if they occur.
        hikari.errors.InternalServerError
            If an internal error occurs on Discord while handling the request.
        """
        return await self.app.rest.create_dm_channel(self.id)

    async def fetch_self(self) -> User:
        """Get this user's up-to-date object by performing an API call.

        Returns
        -------
        hikari.users.User
            The requested user object.

        Raises
        ------
        hikari.errors.NotFoundError
            If the user is not found.
        hikari.errors.RateLimitTooLongError
            Raised in the event that a rate limit occurs that is
            longer than `max_rate_limit` when making a request.
        hikari.errors.RateLimitedError
            Usually, Hikari will handle and retry on hitting
            rate-limits automatically. This includes most bucket-specific
            rate-limits and global rate-limits. In some rare edge cases,
            however, Discord implements other undocumented rules for
            rate-limiting, such as limits per attribute. These cannot be
            detected or handled normally by Hikari due to their undocumented
            nature, and will trigger this exception if they occur.
        hikari.errors.InternalServerError
            If an internal error occurs on Discord while handling the request.
        """
        return await self.app.rest.fetch_user(user=self.id)

    async def send(
        self,
        content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
        *,
        attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
        attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
        component: undefined.UndefinedOr[special_endpoints.ComponentBuilder] = undefined.UNDEFINED,
        components: undefined.UndefinedOr[typing.Sequence[special_endpoints.ComponentBuilder]] = undefined.UNDEFINED,
        embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
        embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
        tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        reply: undefined.UndefinedOr[snowflakes.SnowflakeishOr[messages.PartialMessage]] = undefined.UNDEFINED,
        mentions_everyone: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        mentions_reply: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        user_mentions: undefined.UndefinedOr[
            typing.Union[snowflakes.SnowflakeishSequence[PartialUser], bool]
        ] = undefined.UNDEFINED,
        role_mentions: undefined.UndefinedOr[
            typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]
        ] = undefined.UNDEFINED,
    ) -> messages.Message:
        """Send a message to this user in DM's.

        Parameters
        ----------
        content : hikari.undefined.UndefinedOr[typing.Any]
            If provided, the message contents. If
            `hikari.undefined.UNDEFINED`, then nothing will be sent
            in the content. Any other value here will be cast to a
            `str`.

            If this is a `hikari.embeds.Embed` and no `embed` nor `embeds` kwarg
            is provided, then this will instead update the embed. This allows
            for simpler syntax when sending an embed alone.

            Likewise, if this is a `hikari.files.Resource`, then the
            content is instead treated as an attachment if no `attachment` and
            no `attachments` kwargs are provided.


        Other Parameters
        ----------------
        attachment : hikari.undefined.UndefinedOr[hikari.files.Resourceish],
            If provided, the message attachment. This can be a resource,
            or string of a path on your computer or a URL.

            Attachments can be passed as many different things, to aid in
            convenience.

            - If a `pathlib.PurePath` or `str` to a valid URL, the
                resource at the given URL will be streamed to Discord when
                sending the message. Subclasses of
                `hikari.files.WebResource` such as
                `hikari.files.URL`,
                `hikari.messages.Attachment`,
                `hikari.emojis.Emoji`,
                `EmbedResource`, etc will also be uploaded this way.
                This will use bit-inception, so only a small percentage of the
                resource will remain in memory at any one time, thus aiding in
                scalability.
            - If a `hikari.files.Bytes` is passed, or a `str`
                that contains a valid data URI is passed, then this is uploaded
                with a randomized file name if not provided.
            - If a `hikari.files.File`, `pathlib.PurePath` or
                `str` that is an absolute or relative path to a file
                on your file system is passed, then this resource is uploaded
                as an attachment using non-blocking code internally and streamed
                using bit-inception where possible. This depends on the
                type of `concurrent.futures.Executor` that is being used for
                the application (default is a thread pool which supports this
                behaviour).
        attachments : hikari.undefined.UndefinedOr[typing.Sequence[hikari.files.Resourceish]],
            If provided, the message attachments. These can be resources, or
            strings consisting of paths on your computer or URLs.
        component : hikari.undefined.UndefinedOr[hikari.api.special_endpoints.ComponentBuilder]
            If provided, builder object of the component to include in this message.
        components : hikari.undefined.UndefinedOr[typing.Sequence[hikari.api.special_endpoints.ComponentBuilder]]
            If provided, a sequence of the component builder objects to include
            in this message.
        embed : hikari.undefined.UndefinedOr[hikari.embeds.Embed]
            If provided, the message embed.
        embeds : hikari.undefined.UndefinedOr[typing.Sequence[hikari.embeds.Embed]]
            If provided, the message embeds.
        tts : hikari.undefined.UndefinedOr[bool]
            If provided, whether the message will be read out by a screen
            reader using Discord's TTS (text-to-speech) system.
        reply : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.messages.PartialMessage]]
            If provided, the message to reply to.
        mentions_everyone : hikari.undefined.UndefinedOr[bool]
            If provided, whether the message should parse @everyone/@here
            mentions.
        mentions_reply : hikari.undefined.UndefinedOr[bool]
            If provided, whether to mention the author of the message
            that is being replied to.

            This will not do anything if not being used with `reply`.
        user_mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.users.PartialUser], bool]]
            If provided, and `True`, all user mentions will be detected.
            If provided, and `False`, all user mentions will be ignored
            if appearing in the message body.
            Alternatively this may be a collection of
            `hikari.snowflakes.Snowflake`, or
            `hikari.users.PartialUser` derivatives to enforce mentioning
            specific users.
        role_mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.guilds.PartialRole], bool]]
            If provided, and `True`, all role mentions will be detected.
            If provided, and `False`, all role mentions will be ignored
            if appearing in the message body.
            Alternatively this may be a collection of
            `hikari.snowflakes.Snowflake`, or
            `hikari.guilds.PartialRole` derivatives to enforce mentioning
            specific roles.

        Returns
        -------
        hikari.messages.Message
            The created message.

        Raises
        ------
        ValueError
            If more than 100 unique objects/entities are passed for
            `role_mentions` or `user_mentions`.
        TypeError
            If both `attachment` and `attachments` are specified.
        hikari.errors.BadRequestError
            This may be raised in several discrete situations, such as messages
            being empty with no attachments or embeds; messages with more than
            2000 characters in them, embeds that exceed one of the many embed
            limits; too many attachments; attachments that are too large;
            invalid image URLs in embeds; `reply` not found or not in the same
            channel; too many components.
        hikari.errors.UnauthorizedError
            If you are unauthorized to make the request (invalid/missing token).
        hikari.errors.ForbiddenError
            If you are missing the `SEND_MESSAGES` in the channel or the
            person you are trying to message has the DM's disabled.
        hikari.errors.NotFoundError
            If the user is not found.
        hikari.errors.RateLimitTooLongError
            Raised in the event that a rate limit occurs that is
            longer than `max_rate_limit` when making a request.
        hikari.errors.RateLimitedError
            Usually, Hikari will handle and retry on hitting
            rate-limits automatically. This includes most bucket-specific
            rate-limits and global rate-limits. In some rare edge cases,
            however, Discord implements other undocumented rules for
            rate-limiting, such as limits per attribute. These cannot be
            detected or handled normally by Hikari due to their undocumented
            nature, and will trigger this exception if they occur.
        hikari.errors.InternalServerError
            If an internal error occurs on Discord while handling the request.
        """  # noqa: E501 - Line too long
        channel_id = None
        if isinstance(self.app, traits.CacheAware):
            channel_id = self.app.cache.get_dm_channel_id(self.id)

        if channel_id is None:
            channel_id = (await self.fetch_dm_channel()).id

        return await self.app.rest.create_message(
            channel=channel_id,
            content=content,
            attachment=attachment,
            attachments=attachments,
            component=component,
            components=components,
            embed=embed,
            embeds=embeds,
            tts=tts,
            reply=reply,
            mentions_everyone=mentions_everyone,
            user_mentions=user_mentions,
            role_mentions=role_mentions,
            mentions_reply=mentions_reply,
        )

A partial interface for a user.

Fields may or may not be present, and should be explicitly checked before using them to ensure they are not hikari.undefined.UNDEFINED.

This is used for endpoints and events that only expose partial user information.

For full user info, consider calling the fetch_self method to perform an API call.

Variables and properties

Custom banner color for the user if set, else None.

Will be hikari.undefined.UNDEFINED if not known.

The official client will decide the default color if not set.

Alias for the accent_color field.

Client application that models may use for procedures.

#  avatar_hash: Union[str, hikari.undefined.UndefinedType, NoneType]

Avatar hash for the user, if they have one, otherwise None.

#  banner_hash: Union[str, hikari.undefined.UndefinedType, NoneType]

Banner hash for the user, if they have one, otherwise hikari.undefined.UNDEFINED.

#  created_at: datetime.datetime

When the object was created.

#  discriminator: Union[str, hikari.undefined.UndefinedType]

Discriminator for the user.

Flag bits that are set for the user.

Return the ID of this entity.

Returns
  • Snowflake: The snowflake ID of this object.

Whether this user is a bot account.

#  is_system: Union[bool, hikari.undefined.UndefinedType]

`Whether this user is a system account.

#  mention: str

Return a raw mention string for the given user.

Example
>>> some_user.mention
'<@123456789123456789>'

Username for the user.

Methods
#  async def fetch_dm_channel(self) -> hikari.channels.DMChannel:
View Source
    async def fetch_dm_channel(self) -> channels.DMChannel:
        """Fetch the DM channel for this user.

        Returns
        -------
        hikari.channels.DMChannel
            The requested channel.

        Raises
        ------
        hikari.errors.UnauthorizedError
            If you are unauthorized to make the request (invalid/missing token).
        hikari.errors.NotFoundError
            If the user is not found.
        hikari.errors.RateLimitTooLongError
            Raised in the event that a rate limit occurs that is
            longer than `max_rate_limit` when making a request.
        hikari.errors.RateLimitedError
            Usually, Hikari will handle and retry on hitting
            rate-limits automatically. This includes most bucket-specific
            rate-limits and global rate-limits. In some rare edge cases,
            however, Discord implements other undocumented rules for
            rate-limiting, such as limits per attribute. These cannot be
            detected or handled normally by Hikari due to their undocumented
            nature, and will trigger this exception if they occur.
        hikari.errors.InternalServerError
            If an internal error occurs on Discord while handling the request.
        """
        return await self.app.rest.create_dm_channel(self.id)

Fetch the DM channel for this user.

Returns
Raises
  • hikari.errors.UnauthorizedError: If you are unauthorized to make the request (invalid/missing token).
  • hikari.errors.NotFoundError: If the user is not found.
  • hikari.errors.RateLimitTooLongError: Raised in the event that a rate limit occurs that is longer than max_rate_limit when making a request.
  • hikari.errors.RateLimitedError: Usually, Hikari will handle and retry on hitting rate-limits automatically. This includes most bucket-specific rate-limits and global rate-limits. In some rare edge cases, however, Discord implements other undocumented rules for rate-limiting, such as limits per attribute. These cannot be detected or handled normally by Hikari due to their undocumented nature, and will trigger this exception if they occur.
  • hikari.errors.InternalServerError: If an internal error occurs on Discord while handling the request.
#  async def fetch_self(self) -> hikari.users.User:
View Source
    async def fetch_self(self) -> User:
        """Get this user's up-to-date object by performing an API call.

        Returns
        -------
        hikari.users.User
            The requested user object.

        Raises
        ------
        hikari.errors.NotFoundError
            If the user is not found.
        hikari.errors.RateLimitTooLongError
            Raised in the event that a rate limit occurs that is
            longer than `max_rate_limit` when making a request.
        hikari.errors.RateLimitedError
            Usually, Hikari will handle and retry on hitting
            rate-limits automatically. This includes most bucket-specific
            rate-limits and global rate-limits. In some rare edge cases,
            however, Discord implements other undocumented rules for
            rate-limiting, such as limits per attribute. These cannot be
            detected or handled normally by Hikari due to their undocumented
            nature, and will trigger this exception if they occur.
        hikari.errors.InternalServerError
            If an internal error occurs on Discord while handling the request.
        """
        return await self.app.rest.fetch_user(user=self.id)

Get this user's up-to-date object by performing an API call.

Returns
Raises
  • hikari.errors.NotFoundError: If the user is not found.
  • hikari.errors.RateLimitTooLongError: Raised in the event that a rate limit occurs that is longer than max_rate_limit when making a request.
  • hikari.errors.RateLimitedError: Usually, Hikari will handle and retry on hitting rate-limits automatically. This includes most bucket-specific rate-limits and global rate-limits. In some rare edge cases, however, Discord implements other undocumented rules for rate-limiting, such as limits per attribute. These cannot be detected or handled normally by Hikari due to their undocumented nature, and will trigger this exception if they occur.
  • hikari.errors.InternalServerError: If an internal error occurs on Discord while handling the request.
#  async def send(
   self,
   content: Union[Any, hikari.undefined.UndefinedType] = UNDEFINED,
   *,
   attachment: Union[hikari.files.Resource[Any], os.PathLike[str], str, bytes, bytearray, memoryview, _io.BytesIO, _io.StringIO, hikari.undefined.UndefinedType] = UNDEFINED,
   attachments: Union[Sequence[Union[hikari.files.Resource[Any], os.PathLike[str], str, bytes, bytearray, memoryview, _io.BytesIO, _io.StringIO]], hikari.undefined.UndefinedType] = UNDEFINED,
   component: Union[hikari.api.special_endpoints.ComponentBuilder, hikari.undefined.UndefinedType] = UNDEFINED,
   components: Union[Sequence[hikari.api.special_endpoints.ComponentBuilder], hikari.undefined.UndefinedType] = UNDEFINED,
   embed: Union[hikari.embeds.Embed, hikari.undefined.UndefinedType] = UNDEFINED,
   embeds: Union[Sequence[hikari.embeds.Embed], hikari.undefined.UndefinedType] = UNDEFINED,
   tts: Union[bool, hikari.undefined.UndefinedType] = UNDEFINED,
   reply: Union[hikari.messages.PartialMessage, hikari.snowflakes.Snowflake, int, hikari.undefined.UndefinedType] = UNDEFINED,
   mentions_everyone: Union[bool, hikari.undefined.UndefinedType] = UNDEFINED,
   mentions_reply: Union[bool, hikari.undefined.UndefinedType] = UNDEFINED,
   user_mentions: Union[Sequence[Union[hikari.users.PartialUser, hikari.snowflakes.Snowflake, int]], bool, hikari.undefined.UndefinedType] = UNDEFINED,
   role_mentions: Union[Sequence[Union[hikari.guilds.PartialRole, hikari.snowflakes.Snowflake, int]], bool, hikari.undefined.UndefinedType] = UNDEFINED
) -> hikari.messages.Message:
View Source
    async def send(
        self,
        content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
        *,
        attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
        attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
        component: undefined.UndefinedOr[special_endpoints.ComponentBuilder] = undefined.UNDEFINED,
        components: undefined.UndefinedOr[typing.Sequence[special_endpoints.ComponentBuilder]] = undefined.UNDEFINED,
        embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
        embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
        tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        reply: undefined.UndefinedOr[snowflakes.SnowflakeishOr[messages.PartialMessage]] = undefined.UNDEFINED,
        mentions_everyone: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        mentions_reply: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        user_mentions: undefined.UndefinedOr[
            typing.Union[snowflakes.SnowflakeishSequence[PartialUser], bool]
        ] = undefined.UNDEFINED,
        role_mentions: undefined.UndefinedOr[
            typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]
        ] = undefined.UNDEFINED,
    ) -> messages.Message:
        """Send a message to this user in DM's.

        Parameters
        ----------
        content : hikari.undefined.UndefinedOr[typing.Any]
            If provided, the message contents. If
            `hikari.undefined.UNDEFINED`, then nothing will be sent
            in the content. Any other value here will be cast to a
            `str`.

            If this is a `hikari.embeds.Embed` and no `embed` nor `embeds` kwarg
            is provided, then this will instead update the embed. This allows
            for simpler syntax when sending an embed alone.

            Likewise, if this is a `hikari.files.Resource`, then the
            content is instead treated as an attachment if no `attachment` and
            no `attachments` kwargs are provided.


        Other Parameters
        ----------------
        attachment : hikari.undefined.UndefinedOr[hikari.files.Resourceish],
            If provided, the message attachment. This can be a resource,
            or string of a path on your computer or a URL.

            Attachments can be passed as many different things, to aid in
            convenience.

            - If a `pathlib.PurePath` or `str` to a valid URL, the
                resource at the given URL will be streamed to Discord when
                sending the message. Subclasses of
                `hikari.files.WebResource` such as
                `hikari.files.URL`,
                `hikari.messages.Attachment`,
                `hikari.emojis.Emoji`,
                `EmbedResource`, etc will also be uploaded this way.
                This will use bit-inception, so only a small percentage of the
                resource will remain in memory at any one time, thus aiding in
                scalability.
            - If a `hikari.files.Bytes` is passed, or a `str`
                that contains a valid data URI is passed, then this is uploaded
                with a randomized file name if not provided.
            - If a `hikari.files.File`, `pathlib.PurePath` or
                `str` that is an absolute or relative path to a file
                on your file system is passed, then this resource is uploaded
                as an attachment using non-blocking code internally and streamed
                using bit-inception where possible. This depends on the
                type of `concurrent.futures.Executor` that is being used for
                the application (default is a thread pool which supports this
                behaviour).
        attachments : hikari.undefined.UndefinedOr[typing.Sequence[hikari.files.Resourceish]],
            If provided, the message attachments. These can be resources, or
            strings consisting of paths on your computer or URLs.
        component : hikari.undefined.UndefinedOr[hikari.api.special_endpoints.ComponentBuilder]
            If provided, builder object of the component to include in this message.
        components : hikari.undefined.UndefinedOr[typing.Sequence[hikari.api.special_endpoints.ComponentBuilder]]
            If provided, a sequence of the component builder objects to include
            in this message.
        embed : hikari.undefined.UndefinedOr[hikari.embeds.Embed]
            If provided, the message embed.
        embeds : hikari.undefined.UndefinedOr[typing.Sequence[hikari.embeds.Embed]]
            If provided, the message embeds.
        tts : hikari.undefined.UndefinedOr[bool]
            If provided, whether the message will be read out by a screen
            reader using Discord's TTS (text-to-speech) system.
        reply : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.messages.PartialMessage]]
            If provided, the message to reply to.
        mentions_everyone : hikari.undefined.UndefinedOr[bool]
            If provided, whether the message should parse @everyone/@here
            mentions.
        mentions_reply : hikari.undefined.UndefinedOr[bool]
            If provided, whether to mention the author of the message
            that is being replied to.

            This will not do anything if not being used with `reply`.
        user_mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.users.PartialUser], bool]]
            If provided, and `True`, all user mentions will be detected.
            If provided, and `False`, all user mentions will be ignored
            if appearing in the message body.
            Alternatively this may be a collection of
            `hikari.snowflakes.Snowflake`, or
            `hikari.users.PartialUser` derivatives to enforce mentioning
            specific users.
        role_mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.guilds.PartialRole], bool]]
            If provided, and `True`, all role mentions will be detected.
            If provided, and `False`, all role mentions will be ignored
            if appearing in the message body.
            Alternatively this may be a collection of
            `hikari.snowflakes.Snowflake`, or
            `hikari.guilds.PartialRole` derivatives to enforce mentioning
            specific roles.

        Returns
        -------
        hikari.messages.Message
            The created message.

        Raises
        ------
        ValueError
            If more than 100 unique objects/entities are passed for
            `role_mentions` or `user_mentions`.
        TypeError
            If both `attachment` and `attachments` are specified.
        hikari.errors.BadRequestError
            This may be raised in several discrete situations, such as messages
            being empty with no attachments or embeds; messages with more than
            2000 characters in them, embeds that exceed one of the many embed
            limits; too many attachments; attachments that are too large;
            invalid image URLs in embeds; `reply` not found or not in the same
            channel; too many components.
        hikari.errors.UnauthorizedError
            If you are unauthorized to make the request (invalid/missing token).
        hikari.errors.ForbiddenError
            If you are missing the `SEND_MESSAGES` in the channel or the
            person you are trying to message has the DM's disabled.
        hikari.errors.NotFoundError
            If the user is not found.
        hikari.errors.RateLimitTooLongError
            Raised in the event that a rate limit occurs that is
            longer than `max_rate_limit` when making a request.
        hikari.errors.RateLimitedError
            Usually, Hikari will handle and retry on hitting
            rate-limits automatically. This includes most bucket-specific
            rate-limits and global rate-limits. In some rare edge cases,
            however, Discord implements other undocumented rules for
            rate-limiting, such as limits per attribute. These cannot be
            detected or handled normally by Hikari due to their undocumented
            nature, and will trigger this exception if they occur.
        hikari.errors.InternalServerError
            If an internal error occurs on Discord while handling the request.
        """  # noqa: E501 - Line too long
        channel_id = None
        if isinstance(self.app, traits.CacheAware):
            channel_id = self.app.cache.get_dm_channel_id(self.id)

        if channel_id is None:
            channel_id = (await self.fetch_dm_channel()).id

        return await self.app.rest.create_message(
            channel=channel_id,
            content=content,
            attachment=attachment,
            attachments=attachments,
            component=component,
            components=components,
            embed=embed,
            embeds=embeds,
            tts=tts,
            reply=reply,
            mentions_everyone=mentions_everyone,
            user_mentions=user_mentions,
            role_mentions=role_mentions,
            mentions_reply=mentions_reply,
        )

Send a message to this user in DM's.

Parameters
  • content (hikari.undefined.UndefinedOr[typing.Any]): If provided, the message contents. If hikari.undefined.UNDEFINED, then nothing will be sent in the content. Any other value here will be cast to a str.

    If this is a hikari.embeds.Embed and no embed nor embeds kwarg is provided, then this will instead update the embed. This allows for simpler syntax when sending an embed alone.

    Likewise, if this is a hikari.files.Resource, then the content is instead treated as an attachment if no attachment and no attachments kwargs are provided.

Other Parameters
Returns
Raises
  • ValueError: If more than 100 unique objects/entities are passed for role_mentions or user_mentions.
  • TypeError: If both attachment and attachments are specified.
  • hikari.errors.BadRequestError: This may be raised in several discrete situations, such as messages being empty with no attachments or embeds; messages with more than 2000 characters in them, embeds that exceed one of the many embed limits; too many attachments; attachments that are too large; invalid image URLs in embeds; reply not found or not in the same channel; too many components.
  • hikari.errors.UnauthorizedError: If you are unauthorized to make the request (invalid/missing token).
  • hikari.errors.ForbiddenError: If you are missing the SEND_MESSAGES in the channel or the person you are trying to message has the DM's disabled.
  • hikari.errors.NotFoundError: If the user is not found.
  • hikari.errors.RateLimitTooLongError: Raised in the event that a rate limit occurs that is longer than max_rate_limit when making a request.
  • hikari.errors.RateLimitedError: Usually, Hikari will handle and retry on hitting rate-limits automatically. This includes most bucket-specific rate-limits and global rate-limits. In some rare edge cases, however, Discord implements other undocumented rules for rate-limiting, such as limits per attribute. These cannot be detected or handled normally by Hikari due to their undocumented nature, and will trigger this exception if they occur.
  • hikari.errors.InternalServerError: If an internal error occurs on Discord while handling the request.
#  
@typing.final
class PremiumType(builtins.int, hikari.internal.enums.Enum):
View Source
@typing.final
class PremiumType(int, enums.Enum):
    """The types of Nitro."""

    NONE = 0
    """No premium."""

    NITRO_CLASSIC = 1
    """Premium including basic perks like animated emojis and avatars."""

    NITRO = 2
    """Premium including all perks (e.g. 2 server boosts)."""

The types of Nitro.

Variables and properties
#  NITRO

Premium including all perks (e.g. 2 server boosts).

#  NITRO_CLASSIC

Premium including basic perks like animated emojis and avatars.

#  NONE

No premium.

#  denominator

the denominator of a rational number in lowest terms

#  imag

the imaginary part of a complex number

#  name: str

Return the name of the enum member as a str.

#  numerator

the numerator of a rational number in lowest terms

#  real

the real part of a complex number

#  value

Return the value of the enum member.

Methods
#  def __init__(cls, value: Any):
View Source
    def __call__(cls, value: typing.Any) -> typing.Any:
        """Cast a value to the enum, returning the raw value that was passed if value not found."""
        try:
            return cls._value_to_member_map_[value]
        except KeyError:
            # If we can't find the value, just return what got casted in
            return value

Cast a value to the enum, returning the raw value that was passed if value not found.

#  def as_integer_ratio(self, /):

Return integer ratio.

Return a pair of integers, whose ratio is exactly equal to the original int and with a positive denominator.

>>> (10).as_integer_ratio()
(10, 1)
>>> (-10).as_integer_ratio()
(-10, 1)
>>> (0).as_integer_ratio()
(0, 1)
#  def bit_length(self, /):

Number of bits necessary to represent self in binary.

>>> bin(37)
'0b100101'
>>> (37).bit_length()
6
#  def conjugate(unknown):

Returns self, the complex conjugate of any int.

#  def from_bytes(type, /, bytes, byteorder, *, signed=False):

Return the integer represented by the given array of bytes.

bytes Holds the array of bytes to convert. The argument must either support the buffer protocol or be an iterable object producing bytes. Bytes and bytearray are examples of built-in objects that support the buffer protocol. byteorder The byte order used to represent the integer. If byteorder is 'big', the most significant byte is at the beginning of the byte array. If byteorder is 'little', the most significant byte is at the end of the byte array. To request the native byte order of the host system, use `sys.byteorder' as the byte order value. signed Indicates whether two's complement is used to represent the integer.

#  def to_bytes(self, /, length, byteorder, *, signed=False):

Return an array of bytes representing an integer.

length Length of bytes object to use. An OverflowError is raised if the integer is not representable with the given number of bytes. byteorder The byte order used to represent the integer. If byteorder is 'big', the most significant byte is at the beginning of the byte array. If byteorder is 'little', the most significant byte is at the end of the byte array. To request the native byte order of the host system, use `sys.byteorder' as the byte order value. signed Determines whether two's complement is used to represent the integer. If signed is False and a negative integer is given, an OverflowError is raised.

#  class User(PartialUser, abc.ABC):
View Source
class User(PartialUser, abc.ABC):
    """Interface for any user-like object.

    This does not include partial users, as they may not be fully formed.
    """

    __slots__: typing.Sequence[str] = ()

    @property
    @abc.abstractmethod
    def app(self) -> traits.RESTAware:
        """Client application that models may use for procedures."""

    @property
    @abc.abstractmethod
    def accent_color(self) -> typing.Optional[colors.Color]:
        """The custom banner color for the user, if set else `None`.

        The official client will decide the default color if not set.
        """  # noqa: D401 - Imperative mood

    @property
    def accent_colour(self) -> typing.Optional[colors.Color]:
        """Alias for the `accent_color` field."""
        return self.accent_color

    @property
    @abc.abstractmethod
    def avatar_hash(self) -> typing.Optional[str]:
        """Avatar hash for the user, if they have one, otherwise `None`."""

    @property
    def avatar_url(self) -> typing.Optional[files.URL]:
        """Avatar URL for the user, if they have one set.

        May be `None` if no custom avatar is set. In this case, you
        should use `default_avatar_url` instead.
        """
        return self.make_avatar_url()

    @property
    @abc.abstractmethod
    def banner_hash(self) -> typing.Optional[str]:
        """Banner hash for the user, if they have one, otherwise `hikari.undefined.UNDEFINED`."""

    @property
    def banner_url(self) -> typing.Optional[files.URL]:
        """Banner URL for the user, if they have one set.

        May be `None` if no custom banner is set.
        """
        return self.make_banner_url()

    @property
    def default_avatar_url(self) -> files.URL:
        """Default avatar URL for this user."""  # noqa: D401 - Imperative mood
        return routes.CDN_DEFAULT_USER_AVATAR.compile_to_file(
            urls.CDN_URL,
            discriminator=int(self.discriminator) % 5,
            file_format="png",
        )

    @property
    def display_avatar_url(self) -> files.URL:
        """Display avatar URL for this user."""
        return self.make_avatar_url() or self.default_avatar_url

    @property
    @abc.abstractmethod
    def discriminator(self) -> str:
        """Discriminator for the user."""

    @property
    @abc.abstractmethod
    def flags(self) -> UserFlag:
        """Flag bits that are set for the user."""

    @property
    @abc.abstractmethod
    def is_bot(self) -> bool:
        """Whether this user is a bot account."""

    @property
    @abc.abstractmethod
    def is_system(self) -> bool:
        """Whether this user is a system account."""

    @property
    @abc.abstractmethod
    def mention(self) -> str:
        """Return a raw mention string for the given user.

        Example
        -------
        ```py
        >>> some_user.mention
        '<@123456789123456789>'
        ```
        """

    @property
    @abc.abstractmethod
    def username(self) -> str:
        """Username for the user."""

    def make_avatar_url(self, *, ext: typing.Optional[str] = None, size: int = 4096) -> typing.Optional[files.URL]:
        """Generate the avatar URL for this user, if set.

        If no custom avatar is set, this returns `None`. You can then
        use the `default_avatar_url` attribute instead to fetch the displayed
        URL.

        Parameters
        ----------
        ext : typing.Optional[str]
            The ext to use for this URL, defaults to `png` or `gif`.
            Supports `png`, `jpeg`, `jpg`, `webp` and `gif` (when
            animated). Will be ignored for default avatars which can only be
            `png`.

            If `None`, then the correct default extension is
            determined based on whether the icon is animated or not.
        size : int
            The size to set for the URL, defaults to `4096`.
            Can be any power of two between 16 and 4096.
            Will be ignored for default avatars.

        Returns
        -------
        typing.Optional[hikari.files.URL]
            The URL to the avatar, or `None` if not present.

        Raises
        ------
        ValueError
            If `size` is not a power of two or not between 16 and 4096.
        """
        if self.avatar_hash is None:
            return None

        if ext is None:
            if self.avatar_hash.startswith("a_"):
                ext = "gif"
            else:
                ext = "png"

        return routes.CDN_USER_AVATAR.compile_to_file(
            urls.CDN_URL,
            user_id=self.id,
            hash=self.avatar_hash,
            size=size,
            file_format=ext,
        )

    def make_banner_url(self, *, ext: typing.Optional[str] = None, size: int = 4096) -> typing.Optional[files.URL]:
        """Generate the banner URL for this user, if set.

        If no custom banner is set, this returns `None`.

        Parameters
        ----------
        ext : typing.Optional[str]
            The ext to use for this URL, defaults to `png` or `gif`.
            Supports `png`, `jpeg`, `jpg`, `webp` and `gif` (when
            animated).

            If `None`, then the correct default extension is
            determined based on whether the banner is animated or not.
        size : int
            The size to set for the URL, defaults to `4096`.
            Can be any power of two between 16 and 4096.

        Returns
        -------
        typing.Optional[hikari.files.URL]
            The URL to the banner, or `None` if not present.

        Raises
        ------
        ValueError
            If `size` is not a power of two or not between 16 and 4096.
        """
        if self.banner_hash is None:
            return None

        if ext is None:
            if self.banner_hash.startswith("a_"):
                ext = "gif"
            else:
                ext = "png"

        return routes.CDN_USER_BANNER.compile_to_file(
            urls.CDN_URL,
            user_id=self.id,
            hash=self.banner_hash,
            size=size,
            file_format=ext,
        )

Interface for any user-like object.

This does not include partial users, as they may not be fully formed.

Variables and properties
#  accent_color: Optional[hikari.colors.Color]

The custom banner color for the user, if set else None.

The official client will decide the default color if not set.

#  accent_colour: Optional[hikari.colors.Color]

Alias for the accent_color field.

Client application that models may use for procedures.

#  avatar_hash: Optional[str]

Avatar hash for the user, if they have one, otherwise None.

#  avatar_url: Optional[hikari.files.URL]

Avatar URL for the user, if they have one set.

May be None if no custom avatar is set. In this case, you should use default_avatar_url instead.

#  banner_hash: Optional[str]

Banner hash for the user, if they have one, otherwise hikari.undefined.UNDEFINED.

#  banner_url: Optional[hikari.files.URL]

Banner URL for the user, if they have one set.

May be None if no custom banner is set.

#  created_at: datetime.datetime

When the object was created.

#  default_avatar_url: hikari.files.URL

Default avatar URL for this user.

#  discriminator: str

Discriminator for the user.

#  display_avatar_url: hikari.files.URL

Display avatar URL for this user.

Flag bits that are set for the user.

Return the ID of this entity.

Returns
  • Snowflake: The snowflake ID of this object.
#  is_bot: bool

Whether this user is a bot account.

#  is_system: bool

Whether this user is a system account.

#  mention: str

Return a raw mention string for the given user.

Example
>>> some_user.mention
'<@123456789123456789>'
#  username: str

Username for the user.

Methods
#  async def fetch_dm_channel(self) -> hikari.channels.DMChannel:
View Source
    async def fetch_dm_channel(self) -> channels.DMChannel:
        """Fetch the DM channel for this user.

        Returns
        -------
        hikari.channels.DMChannel
            The requested channel.

        Raises
        ------
        hikari.errors.UnauthorizedError
            If you are unauthorized to make the request (invalid/missing token).
        hikari.errors.NotFoundError
            If the user is not found.
        hikari.errors.RateLimitTooLongError
            Raised in the event that a rate limit occurs that is
            longer than `max_rate_limit` when making a request.
        hikari.errors.RateLimitedError
            Usually, Hikari will handle and retry on hitting
            rate-limits automatically. This includes most bucket-specific
            rate-limits and global rate-limits. In some rare edge cases,
            however, Discord implements other undocumented rules for
            rate-limiting, such as limits per attribute. These cannot be
            detected or handled normally by Hikari due to their undocumented
            nature, and will trigger this exception if they occur.
        hikari.errors.InternalServerError
            If an internal error occurs on Discord while handling the request.
        """
        return await self.app.rest.create_dm_channel(self.id)

Fetch the DM channel for this user.

Returns
Raises
  • hikari.errors.UnauthorizedError: If you are unauthorized to make the request (invalid/missing token).
  • hikari.errors.NotFoundError: If the user is not found.
  • hikari.errors.RateLimitTooLongError: Raised in the event that a rate limit occurs that is longer than max_rate_limit when making a request.
  • hikari.errors.RateLimitedError: Usually, Hikari will handle and retry on hitting rate-limits automatically. This includes most bucket-specific rate-limits and global rate-limits. In some rare edge cases, however, Discord implements other undocumented rules for rate-limiting, such as limits per attribute. These cannot be detected or handled normally by Hikari due to their undocumented nature, and will trigger this exception if they occur.
  • hikari.errors.InternalServerError: If an internal error occurs on Discord while handling the request.
#  async def fetch_self(self) -> hikari.users.User:
View Source
    async def fetch_self(self) -> User:
        """Get this user's up-to-date object by performing an API call.

        Returns
        -------
        hikari.users.User
            The requested user object.

        Raises
        ------
        hikari.errors.NotFoundError
            If the user is not found.
        hikari.errors.RateLimitTooLongError
            Raised in the event that a rate limit occurs that is
            longer than `max_rate_limit` when making a request.
        hikari.errors.RateLimitedError
            Usually, Hikari will handle and retry on hitting
            rate-limits automatically. This includes most bucket-specific
            rate-limits and global rate-limits. In some rare edge cases,
            however, Discord implements other undocumented rules for
            rate-limiting, such as limits per attribute. These cannot be
            detected or handled normally by Hikari due to their undocumented
            nature, and will trigger this exception if they occur.
        hikari.errors.InternalServerError
            If an internal error occurs on Discord while handling the request.
        """
        return await self.app.rest.fetch_user(user=self.id)

Get this user's up-to-date object by performing an API call.

Returns
Raises
  • hikari.errors.NotFoundError: If the user is not found.
  • hikari.errors.RateLimitTooLongError: Raised in the event that a rate limit occurs that is longer than max_rate_limit when making a request.
  • hikari.errors.RateLimitedError: Usually, Hikari will handle and retry on hitting rate-limits automatically. This includes most bucket-specific rate-limits and global rate-limits. In some rare edge cases, however, Discord implements other undocumented rules for rate-limiting, such as limits per attribute. These cannot be detected or handled normally by Hikari due to their undocumented nature, and will trigger this exception if they occur.
  • hikari.errors.InternalServerError: If an internal error occurs on Discord while handling the request.
#  def make_avatar_url(
   self,
   *,
   ext: Optional[str] = None,
   size: int = 4096
) -> Optional[hikari.files.URL]:
View Source
    def make_avatar_url(self, *, ext: typing.Optional[str] = None, size: int = 4096) -> typing.Optional[files.URL]:
        """Generate the avatar URL for this user, if set.

        If no custom avatar is set, this returns `None`. You can then
        use the `default_avatar_url` attribute instead to fetch the displayed
        URL.

        Parameters
        ----------
        ext : typing.Optional[str]
            The ext to use for this URL, defaults to `png` or `gif`.
            Supports `png`, `jpeg`, `jpg`, `webp` and `gif` (when
            animated). Will be ignored for default avatars which can only be
            `png`.

            If `None`, then the correct default extension is
            determined based on whether the icon is animated or not.
        size : int
            The size to set for the URL, defaults to `4096`.
            Can be any power of two between 16 and 4096.
            Will be ignored for default avatars.

        Returns
        -------
        typing.Optional[hikari.files.URL]
            The URL to the avatar, or `None` if not present.

        Raises
        ------
        ValueError
            If `size` is not a power of two or not between 16 and 4096.
        """
        if self.avatar_hash is None:
            return None

        if ext is None:
            if self.avatar_hash.startswith("a_"):
                ext = "gif"
            else:
                ext = "png"

        return routes.CDN_USER_AVATAR.compile_to_file(
            urls.CDN_URL,
            user_id=self.id,
            hash=self.avatar_hash,
            size=size,
            file_format=ext,
        )

Generate the avatar URL for this user, if set.

If no custom avatar is set, this returns None. You can then use the default_avatar_url attribute instead to fetch the displayed URL.

Parameters
  • ext (typing.Optional[str]): The ext to use for this URL, defaults to png or gif. Supports png, jpeg, jpg, webp and gif (when animated). Will be ignored for default avatars which can only be png.

    If None, then the correct default extension is determined based on whether the icon is animated or not.

  • size (int): The size to set for the URL, defaults to 4096. Can be any power of two between 16 and 4096. Will be ignored for default avatars.
Returns
  • typing.Optional[hikari.files.URL]: The URL to the avatar, or None if not present.
Raises
  • ValueError: If size is not a power of two or not between 16 and 4096.
#  def make_banner_url(
   self,
   *,
   ext: Optional[str] = None,
   size: int = 4096
) -> Optional[hikari.files.URL]:
View Source
    def make_banner_url(self, *, ext: typing.Optional[str] = None, size: int = 4096) -> typing.Optional[files.URL]:
        """Generate the banner URL for this user, if set.

        If no custom banner is set, this returns `None`.

        Parameters
        ----------
        ext : typing.Optional[str]
            The ext to use for this URL, defaults to `png` or `gif`.
            Supports `png`, `jpeg`, `jpg`, `webp` and `gif` (when
            animated).

            If `None`, then the correct default extension is
            determined based on whether the banner is animated or not.
        size : int
            The size to set for the URL, defaults to `4096`.
            Can be any power of two between 16 and 4096.

        Returns
        -------
        typing.Optional[hikari.files.URL]
            The URL to the banner, or `None` if not present.

        Raises
        ------
        ValueError
            If `size` is not a power of two or not between 16 and 4096.
        """
        if self.banner_hash is None:
            return None

        if ext is None:
            if self.banner_hash.startswith("a_"):
                ext = "gif"
            else:
                ext = "png"

        return routes.CDN_USER_BANNER.compile_to_file(
            urls.CDN_URL,
            user_id=self.id,
            hash=self.banner_hash,
            size=size,
            file_format=ext,
        )

Generate the banner URL for this user, if set.

If no custom banner is set, this returns None.

Parameters
  • ext (typing.Optional[str]): The ext to use for this URL, defaults to png or gif. Supports png, jpeg, jpg, webp and gif (when animated).

    If None, then the correct default extension is determined based on whether the banner is animated or not.

  • size (int): The size to set for the URL, defaults to 4096. Can be any power of two between 16 and 4096.
Returns
  • typing.Optional[hikari.files.URL]: The URL to the banner, or None if not present.
Raises
  • ValueError: If size is not a power of two or not between 16 and 4096.
#  async def send(
   self,
   content: Union[Any, hikari.undefined.UndefinedType] = UNDEFINED,
   *,
   attachment: Union[hikari.files.Resource[Any], os.PathLike[str], str, bytes, bytearray, memoryview, _io.BytesIO, _io.StringIO, hikari.undefined.UndefinedType] = UNDEFINED,
   attachments: Union[Sequence[Union[hikari.files.Resource[Any], os.PathLike[str], str, bytes, bytearray, memoryview, _io.BytesIO, _io.StringIO]], hikari.undefined.UndefinedType] = UNDEFINED,
   component: Union[hikari.api.special_endpoints.ComponentBuilder, hikari.undefined.UndefinedType] = UNDEFINED,
   components: Union[Sequence[hikari.api.special_endpoints.ComponentBuilder], hikari.undefined.UndefinedType] = UNDEFINED,
   embed: Union[hikari.embeds.Embed, hikari.undefined.UndefinedType] = UNDEFINED,
   embeds: Union[Sequence[hikari.embeds.Embed], hikari.undefined.UndefinedType] = UNDEFINED,
   tts: Union[bool, hikari.undefined.UndefinedType] = UNDEFINED,
   reply: Union[hikari.messages.PartialMessage, hikari.snowflakes.Snowflake, int, hikari.undefined.UndefinedType] = UNDEFINED,
   mentions_everyone: Union[bool, hikari.undefined.UndefinedType] = UNDEFINED,
   mentions_reply: Union[bool, hikari.undefined.UndefinedType] = UNDEFINED,
   user_mentions: Union[Sequence[Union[hikari.users.PartialUser, hikari.snowflakes.Snowflake, int]], bool, hikari.undefined.UndefinedType] = UNDEFINED,
   role_mentions: Union[Sequence[Union[hikari.guilds.PartialRole, hikari.snowflakes.Snowflake, int]], bool, hikari.undefined.UndefinedType] = UNDEFINED
) -> hikari.messages.Message:
View Source
    async def send(
        self,
        content: undefined.UndefinedOr[typing.Any] = undefined.UNDEFINED,
        *,
        attachment: undefined.UndefinedOr[files.Resourceish] = undefined.UNDEFINED,
        attachments: undefined.UndefinedOr[typing.Sequence[files.Resourceish]] = undefined.UNDEFINED,
        component: undefined.UndefinedOr[special_endpoints.ComponentBuilder] = undefined.UNDEFINED,
        components: undefined.UndefinedOr[typing.Sequence[special_endpoints.ComponentBuilder]] = undefined.UNDEFINED,
        embed: undefined.UndefinedOr[embeds_.Embed] = undefined.UNDEFINED,
        embeds: undefined.UndefinedOr[typing.Sequence[embeds_.Embed]] = undefined.UNDEFINED,
        tts: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        reply: undefined.UndefinedOr[snowflakes.SnowflakeishOr[messages.PartialMessage]] = undefined.UNDEFINED,
        mentions_everyone: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        mentions_reply: undefined.UndefinedOr[bool] = undefined.UNDEFINED,
        user_mentions: undefined.UndefinedOr[
            typing.Union[snowflakes.SnowflakeishSequence[PartialUser], bool]
        ] = undefined.UNDEFINED,
        role_mentions: undefined.UndefinedOr[
            typing.Union[snowflakes.SnowflakeishSequence[guilds.PartialRole], bool]
        ] = undefined.UNDEFINED,
    ) -> messages.Message:
        """Send a message to this user in DM's.

        Parameters
        ----------
        content : hikari.undefined.UndefinedOr[typing.Any]
            If provided, the message contents. If
            `hikari.undefined.UNDEFINED`, then nothing will be sent
            in the content. Any other value here will be cast to a
            `str`.

            If this is a `hikari.embeds.Embed` and no `embed` nor `embeds` kwarg
            is provided, then this will instead update the embed. This allows
            for simpler syntax when sending an embed alone.

            Likewise, if this is a `hikari.files.Resource`, then the
            content is instead treated as an attachment if no `attachment` and
            no `attachments` kwargs are provided.


        Other Parameters
        ----------------
        attachment : hikari.undefined.UndefinedOr[hikari.files.Resourceish],
            If provided, the message attachment. This can be a resource,
            or string of a path on your computer or a URL.

            Attachments can be passed as many different things, to aid in
            convenience.

            - If a `pathlib.PurePath` or `str` to a valid URL, the
                resource at the given URL will be streamed to Discord when
                sending the message. Subclasses of
                `hikari.files.WebResource` such as
                `hikari.files.URL`,
                `hikari.messages.Attachment`,
                `hikari.emojis.Emoji`,
                `EmbedResource`, etc will also be uploaded this way.
                This will use bit-inception, so only a small percentage of the
                resource will remain in memory at any one time, thus aiding in
                scalability.
            - If a `hikari.files.Bytes` is passed, or a `str`
                that contains a valid data URI is passed, then this is uploaded
                with a randomized file name if not provided.
            - If a `hikari.files.File`, `pathlib.PurePath` or
                `str` that is an absolute or relative path to a file
                on your file system is passed, then this resource is uploaded
                as an attachment using non-blocking code internally and streamed
                using bit-inception where possible. This depends on the
                type of `concurrent.futures.Executor` that is being used for
                the application (default is a thread pool which supports this
                behaviour).
        attachments : hikari.undefined.UndefinedOr[typing.Sequence[hikari.files.Resourceish]],
            If provided, the message attachments. These can be resources, or
            strings consisting of paths on your computer or URLs.
        component : hikari.undefined.UndefinedOr[hikari.api.special_endpoints.ComponentBuilder]
            If provided, builder object of the component to include in this message.
        components : hikari.undefined.UndefinedOr[typing.Sequence[hikari.api.special_endpoints.ComponentBuilder]]
            If provided, a sequence of the component builder objects to include
            in this message.
        embed : hikari.undefined.UndefinedOr[hikari.embeds.Embed]
            If provided, the message embed.
        embeds : hikari.undefined.UndefinedOr[typing.Sequence[hikari.embeds.Embed]]
            If provided, the message embeds.
        tts : hikari.undefined.UndefinedOr[bool]
            If provided, whether the message will be read out by a screen
            reader using Discord's TTS (text-to-speech) system.
        reply : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.messages.PartialMessage]]
            If provided, the message to reply to.
        mentions_everyone : hikari.undefined.UndefinedOr[bool]
            If provided, whether the message should parse @everyone/@here
            mentions.
        mentions_reply : hikari.undefined.UndefinedOr[bool]
            If provided, whether to mention the author of the message
            that is being replied to.

            This will not do anything if not being used with `reply`.
        user_mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.users.PartialUser], bool]]
            If provided, and `True`, all user mentions will be detected.
            If provided, and `False`, all user mentions will be ignored
            if appearing in the message body.
            Alternatively this may be a collection of
            `hikari.snowflakes.Snowflake`, or
            `hikari.users.PartialUser` derivatives to enforce mentioning
            specific users.
        role_mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.guilds.PartialRole], bool]]
            If provided, and `True`, all role mentions will be detected.
            If provided, and `False`, all role mentions will be ignored
            if appearing in the message body.
            Alternatively this may be a collection of
            `hikari.snowflakes.Snowflake`, or
            `hikari.guilds.PartialRole` derivatives to enforce mentioning
            specific roles.

        Returns
        -------
        hikari.messages.Message
            The created message.

        Raises
        ------
        ValueError
            If more than 100 unique objects/entities are passed for
            `role_mentions` or `user_mentions`.
        TypeError
            If both `attachment` and `attachments` are specified.
        hikari.errors.BadRequestError
            This may be raised in several discrete situations, such as messages
            being empty with no attachments or embeds; messages with more than
            2000 characters in them, embeds that exceed one of the many embed
            limits; too many attachments; attachments that are too large;
            invalid image URLs in embeds; `reply` not found or not in the same
            channel; too many components.
        hikari.errors.UnauthorizedError
            If you are unauthorized to make the request (invalid/missing token).
        hikari.errors.ForbiddenError
            If you are missing the `SEND_MESSAGES` in the channel or the
            person you are trying to message has the DM's disabled.
        hikari.errors.NotFoundError
            If the user is not found.
        hikari.errors.RateLimitTooLongError
            Raised in the event that a rate limit occurs that is
            longer than `max_rate_limit` when making a request.
        hikari.errors.RateLimitedError
            Usually, Hikari will handle and retry on hitting
            rate-limits automatically. This includes most bucket-specific
            rate-limits and global rate-limits. In some rare edge cases,
            however, Discord implements other undocumented rules for
            rate-limiting, such as limits per attribute. These cannot be
            detected or handled normally by Hikari due to their undocumented
            nature, and will trigger this exception if they occur.
        hikari.errors.InternalServerError
            If an internal error occurs on Discord while handling the request.
        """  # noqa: E501 - Line too long
        channel_id = None
        if isinstance(self.app, traits.CacheAware):
            channel_id = self.app.cache.get_dm_channel_id(self.id)

        if channel_id is None:
            channel_id = (await self.fetch_dm_channel()).id

        return await self.app.rest.create_message(
            channel=channel_id,
            content=content,
            attachment=attachment,
            attachments=attachments,
            component=component,
            components=components,
            embed=embed,
            embeds=embeds,
            tts=tts,
            reply=reply,
            mentions_everyone=mentions_everyone,
            user_mentions=user_mentions,
            role_mentions=role_mentions,
            mentions_reply=mentions_reply,
        )

Send a message to this user in DM's.

Parameters
  • content (hikari.undefined.UndefinedOr[typing.Any]): If provided, the message contents. If hikari.undefined.UNDEFINED, then nothing will be sent in the content. Any other value here will be cast to a str.

    If this is a hikari.embeds.Embed and no embed nor embeds kwarg is provided, then this will instead update the embed. This allows for simpler syntax when sending an embed alone.

    Likewise, if this is a hikari.files.Resource, then the content is instead treated as an attachment if no attachment and no attachments kwargs are provided.

Other Parameters
Returns
Raises
  • ValueError: If more than 100 unique objects/entities are passed for role_mentions or user_mentions.
  • TypeError: If both attachment and attachments are specified.
  • hikari.errors.BadRequestError: This may be raised in several discrete situations, such as messages being empty with no attachments or embeds; messages with more than 2000 characters in them, embeds that exceed one of the many embed limits; too many attachments; attachments that are too large; invalid image URLs in embeds; reply not found or not in the same channel; too many components.
  • hikari.errors.UnauthorizedError: If you are unauthorized to make the request (invalid/missing token).
  • hikari.errors.ForbiddenError: If you are missing the SEND_MESSAGES in the channel or the person you are trying to message has the DM's disabled.
  • hikari.errors.NotFoundError: If the user is not found.
  • hikari.errors.RateLimitTooLongError: Raised in the event that a rate limit occurs that is longer than max_rate_limit when making a request.
  • hikari.errors.RateLimitedError: Usually, Hikari will handle and retry on hitting rate-limits automatically. This includes most bucket-specific rate-limits and global rate-limits. In some rare edge cases, however, Discord implements other undocumented rules for rate-limiting, such as limits per attribute. These cannot be detected or handled normally by Hikari due to their undocumented nature, and will trigger this exception if they occur.
  • hikari.errors.InternalServerError: If an internal error occurs on Discord while handling the request.
#  
@typing.final
class UserFlag(builtins.int, hikari.internal.enums.Flag):
View Source
@typing.final
class UserFlag(enums.Flag):
    """The known user flags that represent account badges."""

    NONE = 0
    """None"""

    DISCORD_EMPLOYEE = 1 << 0
    """Discord Employee."""

    PARTNERED_SERVER_OWNER = 1 << 1
    """Owner of a partnered Discord server."""

    HYPESQUAD_EVENTS = 1 << 2
    """HypeSquad Events."""

    BUG_HUNTER_LEVEL_1 = 1 << 3
    """Bug Hunter Level 1."""

    HYPESQUAD_BRAVERY = 1 << 6
    """House of Bravery."""

    HYPESQUAD_BRILLIANCE = 1 << 7
    """House of Brilliance."""

    HYPESQUAD_BALANCE = 1 << 8
    """House of Balance."""

    EARLY_SUPPORTER = 1 << 9
    """Early Supporter."""

    TEAM_USER = 1 << 10
    """Team user."""

    BUG_HUNTER_LEVEL_2 = 1 << 14
    """Bug Hunter Level 2."""

    VERIFIED_BOT = 1 << 16
    """Verified Bot."""

    EARLY_VERIFIED_DEVELOPER = 1 << 17
    """Early verified Bot Developer.

    Only applies to users that verified their account before 20th August 2019.
    """

    DISCORD_CERTIFIED_MODERATOR = 1 << 18
    """Discord Certified Moderator."""

    BOT_HTTP_INTERACTIONS = 1 << 19
    """Bot uses only HTTP interactions and is shown in the active member list."""

The known user flags that represent account badges.

Variables and properties
#  BOT_HTTP_INTERACTIONS

Bot uses only HTTP interactions and is shown in the active member list.

#  BUG_HUNTER_LEVEL_1

Bug Hunter Level 1.

#  BUG_HUNTER_LEVEL_2

Bug Hunter Level 2.

#  DISCORD_CERTIFIED_MODERATOR

Discord Certified Moderator.

#  DISCORD_EMPLOYEE

Discord Employee.

#  EARLY_SUPPORTER

Early Supporter.

#  EARLY_VERIFIED_DEVELOPER

Early verified Bot Developer.

Only applies to users that verified their account before 20th August 2019.

#  HYPESQUAD_BALANCE

House of Balance.

#  HYPESQUAD_BRAVERY

House of Bravery.

#  HYPESQUAD_BRILLIANCE

House of Brilliance.

#  HYPESQUAD_EVENTS

HypeSquad Events.

#  NONE

None

#  PARTNERED_SERVER_OWNER

Owner of a partnered Discord server.

#  TEAM_USER

Team user.

#  VERIFIED_BOT

Verified Bot.

#  denominator

the denominator of a rational number in lowest terms

#  imag

the imaginary part of a complex number

#  name: str

Return the name of the flag combination as a str.

#  numerator

the numerator of a rational number in lowest terms

#  real

the real part of a complex number

#  value: int

Return the int value of the flag.

Methods
#  def __init__(cls, value: int = 0):
View Source
    def __call__(cls, value: int = 0) -> typing.Any:
        """Cast a value to the flag enum, returning the raw value that was passed if values not found."""
        # We want to handle value invariantly to avoid issues brought in by different behaviours from sub-classed ints
        # and floats. This also ensures that .__int__ only returns an invariant int.
        value = int(value)
        try:
            return cls._value_to_member_map_[value]
        except KeyError:
            # We only need this ability here usually, so overloading operators
            # is an overkill and would add more overhead.

            if value < 0:
                # Convert to a positive value instead.
                return cls.__everything__ - ~value

            temp_members = cls._temp_members_
            # For huge enums, don't ever cache anything. We could consume masses of memory otherwise
            # (e.g. Permissions)
            try:
                # Try to get a cached value.
                return temp_members[value]
            except KeyError:
                # If we can't find the value, just return what got casted in by generating a pseudomember
                # and caching it. We can't use weakref because int is not weak referenceable, annoyingly.
                pseudomember = cls.__new__(cls, value)
                pseudomember._name_ = None
                pseudomember._value_ = value
                temp_members[value] = pseudomember
                if len(temp_members) > _MAX_CACHED_MEMBERS:
                    temp_members.popitem()

                return pseudomember

Cast a value to the flag enum, returning the raw value that was passed if values not found.

#  def all(self: ~_T, *flags: ~_T) -> bool:
View Source
    def all(self: _T, *flags: _T) -> bool:
        """Check if all of the given flags are part of this value.

        Returns
        -------
        bool
            `True` if any of the given flags are part of this value.
            Otherwise, return `False`.
        """
        return all((flag & self) == flag for flag in flags)

Check if all of the given flags are part of this value.

Returns
  • bool: True if any of the given flags are part of this value. Otherwise, return False.
#  def any(self: ~_T, *flags: ~_T) -> bool:
View Source
    def any(self: _T, *flags: _T) -> bool:
        """Check if any of the given flags are part of this value.

        Returns
        -------
        bool
            `True` if any of the given flags are part of this value.
            Otherwise, return `False`.
        """
        return any((flag & self) == flag for flag in flags)

Check if any of the given flags are part of this value.

Returns
  • bool: True if any of the given flags are part of this value. Otherwise, return False.
#  def as_integer_ratio(self, /):

Return integer ratio.

Return a pair of integers, whose ratio is exactly equal to the original int and with a positive denominator.

>>> (10).as_integer_ratio()
(10, 1)
>>> (-10).as_integer_ratio()
(-10, 1)
>>> (0).as_integer_ratio()
(0, 1)
#  def bit_length(self, /):

Number of bits necessary to represent self in binary.

>>> bin(37)
'0b100101'
>>> (37).bit_length()
6
#  def conjugate(unknown):

Returns self, the complex conjugate of any int.

#  def difference(self: ~_T, other: Union[~_T, int]) -> ~_T:
View Source
    def difference(self: _T, other: typing.Union[_T, int]) -> _T:
        """Perform a set difference with the other set.

        This will return all flags in this set that are not in the other value.

        Equivalent to using the subtraction `-` operator.
        """
        return self.__class__(self & ~int(other))

Perform a set difference with the other set.

This will return all flags in this set that are not in the other value.

Equivalent to using the subtraction - operator.

#  def from_bytes(type, /, bytes, byteorder, *, signed=False):

Return the integer represented by the given array of bytes.

bytes Holds the array of bytes to convert. The argument must either support the buffer protocol or be an iterable object producing bytes. Bytes and bytearray are examples of built-in objects that support the buffer protocol. byteorder The byte order used to represent the integer. If byteorder is 'big', the most significant byte is at the beginning of the byte array. If byteorder is 'little', the most significant byte is at the end of the byte array. To request the native byte order of the host system, use `sys.byteorder' as the byte order value. signed Indicates whether two's complement is used to represent the integer.

#  def intersection(self: ~_T, other: Union[~_T, int]) -> ~_T:
View Source
    def intersection(self: _T, other: typing.Union[_T, int]) -> _T:
        """Return a combination of flags that are set for both given values.

        Equivalent to using the "AND" `&` operator.
        """
        return self.__class__(self._value_ & int(other))

Return a combination of flags that are set for both given values.

Equivalent to using the "AND" & operator.

#  def invert(self: ~_T) -> ~_T:
View Source
    def invert(self: _T) -> _T:
        """Return a set of all flags not in the current set."""
        return self.__class__(self.__class__.__everything__._value_ & ~self._value_)

Return a set of all flags not in the current set.

#  def is_disjoint(self: ~_T, other: Union[~_T, int]) -> bool:
View Source
    def is_disjoint(self: _T, other: typing.Union[_T, int]) -> bool:
        """Return whether two sets have a intersection or not.

        If the two sets have an intersection, then this returns
        `False`. If no common flag values exist between them, then
        this returns `True`.
        """
        return not (self & other)

Return whether two sets have a intersection or not.

If the two sets have an intersection, then this returns False. If no common flag values exist between them, then this returns True.

#  def is_subset(self: ~_T, other: Union[~_T, int]) -> bool:
View Source
    def is_subset(self: _T, other: typing.Union[_T, int]) -> bool:
        """Return whether another set contains this set or not.

        Equivalent to using the "in" operator.
        """
        return (self & other) == other

Return whether another set contains this set or not.

Equivalent to using the "in" operator.

#  def is_superset(self: ~_T, other: Union[~_T, int]) -> bool:
View Source
    def is_superset(self: _T, other: typing.Union[_T, int]) -> bool:
        """Return whether this set contains another set or not."""
        return (self & other) == self

Return whether this set contains another set or not.

#  def isdisjoint(self: ~_T, other: Union[~_T, int]) -> bool:
View Source
    def is_disjoint(self: _T, other: typing.Union[_T, int]) -> bool:
        """Return whether two sets have a intersection or not.

        If the two sets have an intersection, then this returns
        `False`. If no common flag values exist between them, then
        this returns `True`.
        """
        return not (self & other)

Return whether two sets have a intersection or not.

If the two sets have an intersection, then this returns False. If no common flag values exist between them, then this returns True.

#  def issubset(self: ~_T, other: Union[~_T, int]) -> bool:
View Source
    def is_subset(self: _T, other: typing.Union[_T, int]) -> bool:
        """Return whether another set contains this set or not.

        Equivalent to using the "in" operator.
        """
        return (self & other) == other

Return whether another set contains this set or not.

Equivalent to using the "in" operator.

#  def issuperset(self: ~_T, other: Union[~_T, int]) -> bool:
View Source
    def is_superset(self: _T, other: typing.Union[_T, int]) -> bool:
        """Return whether this set contains another set or not."""
        return (self & other) == self

Return whether this set contains another set or not.

#  def none(self: ~_T, *flags: ~_T) -> bool:
View Source
    def none(self: _T, *flags: _T) -> bool:
        """Check if none of the given flags are part of this value.

        .. note::
            This is essentially the opposite of `Flag.any`.

        Returns
        -------
        bool
            `True` if none of the given flags are part of this value.
            Otherwise, return `False`.
        """
        return not self.any(*flags)

Check if none of the given flags are part of this value.

Note: This is essentially the opposite of Flag.any.

Returns
  • bool: True if none of the given flags are part of this value. Otherwise, return False.
#  def split(self: ~_T) -> Sequence[~_T]:
View Source
    def split(self: _T) -> typing.Sequence[_T]:
        """Return a list of all defined atomic values for this flag.

        Any unrecognised bits will be omitted for brevity.

        The result will be a name-sorted `typing.Sequence` of each member
        """
        return sorted(
            (member for member in self.__class__._powers_of_2_to_member_map_.values() if member.value & self),
            # Assumption: powers of 2 already have a cached value.
            key=lambda m: m._name_,
        )

Return a list of all defined atomic values for this flag.

Any unrecognised bits will be omitted for brevity.

The result will be a name-sorted typing.Sequence of each member

#  def symmetric_difference(self: ~_T, other: Union[~_T, int]) -> ~_T:
View Source
    def symmetric_difference(self: _T, other: typing.Union[_T, int]) -> _T:
        """Return a set with the symmetric differences of two flag sets.

        Equivalent to using the "XOR" `^` operator.

        For `a ^ b`, this can be considered the same as `(a - b) | (b - a)`.
        """
        return self.__class__(self._value_ ^ int(other))

Return a set with the symmetric differences of two flag sets.

Equivalent to using the "XOR" ^ operator.

For a ^ b, this can be considered the same as (a - b) | (b - a).

#  def symmetricdifference(self: ~_T, other: Union[~_T, int]) -> ~_T:
View Source
    def symmetric_difference(self: _T, other: typing.Union[_T, int]) -> _T:
        """Return a set with the symmetric differences of two flag sets.

        Equivalent to using the "XOR" `^` operator.

        For `a ^ b`, this can be considered the same as `(a - b) | (b - a)`.
        """
        return self.__class__(self._value_ ^ int(other))

Return a set with the symmetric differences of two flag sets.

Equivalent to using the "XOR" ^ operator.

For a ^ b, this can be considered the same as (a - b) | (b - a).

#  def to_bytes(self, /, length, byteorder, *, signed=False):

Return an array of bytes representing an integer.

length Length of bytes object to use. An OverflowError is raised if the integer is not representable with the given number of bytes. byteorder The byte order used to represent the integer. If byteorder is 'big', the most significant byte is at the beginning of the byte array. If byteorder is 'little', the most significant byte is at the end of the byte array. To request the native byte order of the host system, use `sys.byteorder' as the byte order value. signed Determines whether two's complement is used to represent the integer. If signed is False and a negative integer is given, an OverflowError is raised.

#  def union(self: ~_T, other: Union[~_T, int]) -> ~_T:
View Source
    def union(self: _T, other: typing.Union[_T, int]) -> _T:
        """Return a combination of all flags in this set and the other set.

        Equivalent to using the "OR" `~` operator.
        """
        return self.__class__(self._value_ | int(other))

Return a combination of all flags in this set and the other set.

Equivalent to using the "OR" ~ operator.