Back to top

hikari.api.config

Core interface for Hikari's configuration dataclasses.

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.
"""Core interface for Hikari's configuration dataclasses."""
from __future__ import annotations

__all__: typing.Sequence[str] = ("CacheComponents",)

import abc
import typing

from hikari.internal import enums

if typing.TYPE_CHECKING:
    import ssl as ssl_


class CacheComponents(enums.Flag):
    """Flags to control the cache components."""

    NONE = 0
    """Disables the cache."""

    GUILDS = 1 << 0
    """Enables the guild cache."""

    GUILD_CHANNELS = 1 << 1
    """Enables the guild channels cache."""

    MEMBERS = 1 << 2
    """Enables the members cache."""

    ROLES = 1 << 3
    """Enables the roles cache."""

    INVITES = 1 << 4
    """Enables the invites cache."""

    EMOJIS = 1 << 5
    """Enables the emojis cache."""

    PRESENCES = 1 << 6
    """Enables the presences cache."""

    VOICE_STATES = 1 << 7
    """Enables the voice states cache."""

    MESSAGES = 1 << 8
    """Enables the messages cache."""

    ME = 1 << 9
    """Enables the me cache."""

    DM_CHANNEL_IDS = 1 << 10
    """Enables the DM channel IDs cache."""

    ALL = (
        GUILDS
        | GUILD_CHANNELS
        | MEMBERS
        | ROLES
        | INVITES
        | EMOJIS
        | PRESENCES
        | VOICE_STATES
        | MESSAGES
        | ME
        | DM_CHANNEL_IDS
    )
    """Fully enables the cache."""


class ProxySettings(abc.ABC):
    """Settings for configuring an HTTP-based proxy."""

    __slots__: typing.Sequence[str] = ()

    @property
    @abc.abstractmethod
    def url(self) -> typing.Union[None, str]:
        """Proxy URL to use.

        If this is `None` then no explicit proxy is being used.
        """

    @property
    @abc.abstractmethod
    def trust_env(self) -> bool:
        """Toggle whether to look for a `netrc` file or environment variables.

        If `True`, and no `url` is given on this object, then
        `HTTP_PROXY` and `HTTPS_PROXY` will be used from the environment
        variables, or a `netrc` file may be read to determine credentials.

        If `False`, then this information is instead ignored.

        .. note::
            For more details of using `netrc`, visit:
            https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html
        """


class HTTPSettings(abc.ABC):
    """Settings to control HTTP clients."""

    __slots__: typing.Sequence[str] = ()

    @property
    @abc.abstractmethod
    def max_redirects(self) -> typing.Optional[int]:
        """Behavior for handling redirect HTTP responses.

        If a `int`, allow following redirects from `3xx` HTTP responses
        for up to this many redirects. Exceeding this value will raise an
        exception.

        If `None`, then disallow any redirects.

        The default is to disallow this behavior for security reasons.

        Generally, it is safer to keep this disabled. You may find a case in the
        future where you need to enable this if Discord change their URL without
        warning.

        .. note::
            This will only apply to the REST API. WebSockets remain unaffected
            by any value set here.
        """

    @property
    @abc.abstractmethod
    def ssl(self) -> ssl_.SSLContext:
        """SSL context to use.

        This may be __assigned__ a `bool` or an `ssl.SSLContext` object.

        If assigned to `True`, a default SSL context is generated by
        this class that will enforce SSL verification. This is then stored in
        this field.

        If `False`, then a default SSL context is generated by this
        class that will **NOT** enforce SSL verification. This is then stored
        in this field.

        If an instance of `ssl.SSLContext`, then this context will be used.

        .. warning::
            Setting a custom value here may have security implications, or
            may result in the application being unable to connect to Discord
            at all.

        .. warning::
            Disabling SSL verification is almost always unadvised. This
            is because your application will no longer check whether you are
            connecting to Discord, or to some third party spoof designed
            to steal personal credentials such as your application token.

            There may be cases where SSL certificates do not get updated,
            and in this case, you may find that disabling this explicitly
            allows you to work around any issues that are occurring, but
            you should immediately seek a better solution where possible
            if any form of personal security is in your interest.
        """


class CacheSettings(abc.ABC):
    """Settings to control the cache."""

    __slots__: typing.Sequence[str] = ()

    @property
    @abc.abstractmethod
    def components(self) -> CacheComponents:
        """Cache components to use."""
#  class CacheComponents(builtins.int, hikari.internal.enums.Flag):
View Source
class CacheComponents(enums.Flag):
    """Flags to control the cache components."""

    NONE = 0
    """Disables the cache."""

    GUILDS = 1 << 0
    """Enables the guild cache."""

    GUILD_CHANNELS = 1 << 1
    """Enables the guild channels cache."""

    MEMBERS = 1 << 2
    """Enables the members cache."""

    ROLES = 1 << 3
    """Enables the roles cache."""

    INVITES = 1 << 4
    """Enables the invites cache."""

    EMOJIS = 1 << 5
    """Enables the emojis cache."""

    PRESENCES = 1 << 6
    """Enables the presences cache."""

    VOICE_STATES = 1 << 7
    """Enables the voice states cache."""

    MESSAGES = 1 << 8
    """Enables the messages cache."""

    ME = 1 << 9
    """Enables the me cache."""

    DM_CHANNEL_IDS = 1 << 10
    """Enables the DM channel IDs cache."""

    ALL = (
        GUILDS
        | GUILD_CHANNELS
        | MEMBERS
        | ROLES
        | INVITES
        | EMOJIS
        | PRESENCES
        | VOICE_STATES
        | MESSAGES
        | ME
        | DM_CHANNEL_IDS
    )
    """Fully enables the cache."""

Flags to control the cache components.

Variables and properties

Fully enables the cache.

#  DM_CHANNEL_IDS

Enables the DM channel IDs cache.

#  EMOJIS

Enables the emojis cache.

#  GUILDS

Enables the guild cache.

#  GUILD_CHANNELS

Enables the guild channels cache.

#  INVITES

Enables the invites cache.

Enables the me cache.

#  MEMBERS

Enables the members cache.

#  MESSAGES

Enables the messages cache.

#  NONE

Disables the cache.

#  PRESENCES

Enables the presences cache.

#  ROLES

Enables the roles cache.

#  VOICE_STATES

Enables the voice states cache.

#  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.