diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a527462c27..1b7dc3a67e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -191,15 +191,13 @@ jobs: - name: Setup python uses: actions/setup-python@v5 with: - python-version: 3.9 - - - name: Setup node - uses: actions/setup-node@v4 + # NOTE: This should be kept up to date with .readthedocs.yaml + python-version: 3.11 - name: Build documentation run: | pip install -r dev-requirements.txt - nox -s sphinx + nox -s mkdocs - name: Upload artifacts if: github.event_name == 'pull_request' diff --git a/.readthedocs.yaml b/.readthedocs.yaml index ef6a217ba6..645f48da3f 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -3,26 +3,14 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.9" + # NOTE: This should be kept up to date with .ci.yml + python: "3.11" -sphinx: - configuration: docs/conf.py - builder: dirhtml +mkdocs: + configuration: mkdocs.yml python: install: - - requirements: dev-requirements/sphinx.txt + - requirements: dev-requirements/mkdocs.txt - method: pip path: . - -search: - ignore: - # Defaults - - search.html - - search/index.html - - 404.html - - 404/index.html - - # Custom - - index.html - - changelog/index.html diff --git a/README.md b/README.md index b0b738d747..67b2d5a78a 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Python 3.8, 3.9, 3.10, 3.11 and 3.12 are currently supported. ## Installation -Install Hikari from PyPI with the following command: +Install hikari from PyPI with the following command: ```bash python -m pip install -U hikari @@ -35,6 +35,7 @@ py -3 -m pip install -U hikari ## Bots Hikari provides two different default bot implementations to suit your needs: + - [GatewayBot](#gatewaybot) - [RESTBot](#restbot) @@ -194,6 +195,7 @@ bot.run( Many other helpful options exist for you to take advantage of if you wish. Links to the respective docs can be seen below: + - [GatewayBot.run](https://docs.hikari-py.dev/en/stable/reference/hikari/impl/gateway_bot/#hikari.impl.gateway_bot.GatewayBot.run) - [RESTBot.run](https://docs.hikari-py.dev/en/stable/reference/hikari/impl/rest_bot/#hikari.impl.rest_bot.RESTBot.run) @@ -246,14 +248,20 @@ python -m pip install -U hikari[speedups, server] ## Additional resources -You may wish to use a command framework on top of Hikari so that you can start writing a bot quickly without +You may wish to use a command framework on top of hikari so that you can start writing a bot quickly without implementing your own command handler. Hikari does not include a command framework by default, so you will want to pick a third party library to do it: -- [`lightbulb`](https://github.com/tandemdude/hikari-lightbulb) - a simple and easy to use command framework for Hikari. -- [`tanjun`](https://github.com/FasterSpeeding/Tanjun) - a flexible command framework designed to extend Hikari. -- [`crescent`](https://github.com/magpie-dev/hikari-crescent) - a command handler for Hikari that keeps your project neat and tidy. +- [`arc`](https://github.com/hypergonial/hikari-arc) - a bot framework with a focus on type-safety and correctness. +- [`crescent`](https://github.com/magpie-dev/hikari-crescent) - a command handler for hikari that keeps your project neat and tidy. +- [`lightbulb`](https://github.com/tandemdude/hikari-lightbulb) - a simple and easy to use command framework for hikari. +- [`tanjun`](https://github.com/FasterSpeeding/Tanjun) - a flexible command framework designed to extend hikari. + +There are also third party libraries to help you manage components: + +- [`miru`](https://github.com/hypergonial/hikari-miru) - A component handler for hikari, inspired by discord.py's views. +- [`flare`](https://github.com/brazier-dev/hikari-flare/) - a component manager designed to write simple interactions with persistent data. --- @@ -307,7 +315,7 @@ Currently, this functionality does not yet exist. --- -## Developing Hikari +## Developing hikari To familiarize yourself a bit with the project, we recommend reading our [contributing manual](https://github.com/hikari-py/hikari/blob/master/CONTRIBUTING.md). diff --git a/changes/1810.documentation.md b/changes/1810.documentation.md new file mode 100644 index 0000000000..112f919b1c --- /dev/null +++ b/changes/1810.documentation.md @@ -0,0 +1 @@ +Switch documentation to mkdocs diff --git a/dev-requirements/mkdocs.txt b/dev-requirements/mkdocs.txt new file mode 100644 index 0000000000..58e7a4269b --- /dev/null +++ b/dev-requirements/mkdocs.txt @@ -0,0 +1,18 @@ +mkdocs==1.5.3 + +# Mkdocs Material +mkdocs-material[imaging]==9.5.14 + +# Docstring parsing for API reference +mkdocstrings[python]==0.24.1 +griffe-inherited-docstrings==1.0.0 + +# Generate API reference pages dynamically +mkdocs-gen-files==0.5.0 +mkdocs-literate-nav==0.6.1 + +# Formatting signatures +black==24.3.0 + +# Image viewer ext +mkdocs-glightbox==0.3.7 diff --git a/dev-requirements/sphinx.txt b/dev-requirements/sphinx.txt deleted file mode 100644 index e169bc2d9f..0000000000 --- a/dev-requirements/sphinx.txt +++ /dev/null @@ -1,16 +0,0 @@ -sphinx==7.2.6 - -# Theme -furo==2023.9.10 - -# Autodocumentation -sphinx-autoapi==3.0.0 -numpydoc==1.6.0 - -# Static files -myst-parser==2.0.0 - -# Misc extensions -sphinxext.opengraph==0.9.1 -sphinx-copybutton==0.5.2 -sphinxcontrib-towncrier==0.4.0a0 diff --git a/docs/.gitignore b/docs/.gitignore deleted file mode 100644 index feead5b1fb..0000000000 --- a/docs/.gitignore +++ /dev/null @@ -1 +0,0 @@ -reference/ diff --git a/docs/_static/extra.css b/docs/_static/extra.css deleted file mode 100644 index 7d0dd52db0..0000000000 --- a/docs/_static/extra.css +++ /dev/null @@ -1,47 +0,0 @@ -html { - word-wrap: anywhere; -} - -body { - --toc-item-spacing-horizontal: 0.5rem; - --admonition-font-size: 0.8em; -} - -.icon { - user-select: none; -} - -.viewcode-back { - position: absolute; - right: 1em; - background-color: var(--color-code-background); - width: auto; -} - -.toc-drawer { - width: initial; - max-width: 20em; - right: -20em; -} - -.toc-tree ul ul ul ul { - border-left: 1px solid var(--color-background-border); -} - -@media (max-width: 82em) { - body { - font-size: 0.7em; - } - - .toc-tree { - padding-left: 0; - } - - .sidebar-brand-text { - font-size: 1rem; - } - - .sidebar-tree .reference { - padding: 0.5em 1em; - } -} diff --git a/docs/_templates/numpydoc_docstring.rst b/docs/_templates/numpydoc_docstring.rst deleted file mode 100644 index c3d3f7e317..0000000000 --- a/docs/_templates/numpydoc_docstring.rst +++ /dev/null @@ -1,17 +0,0 @@ -{{index}} -{{summary}} -{{extended_summary}} -{{warns}} -{{warnings}} -{{notes}} -{{parameters}} -{{other_parameters}} -{{returns}} -{{yields}} -{{receives}} -{{raises}} -{{see_also}} -{{references}} -{{examples}} -{{attributes}} -{{methods}} diff --git a/docs/_templates/python/module.rst b/docs/_templates/python/module.rst deleted file mode 100644 index 9f52ac3257..0000000000 --- a/docs/_templates/python/module.rst +++ /dev/null @@ -1,115 +0,0 @@ -{# modified version of https://github.com/readthedocs/sphinx-autoapi/blob/2335e002f8ec2e2fce9ff0e61ba99093929f0764/autoapi/templates/python/module.rst #} -{% if not obj.display %} -:orphan: - -{% endif %} -{{ obj.name }} -{{ "=" * obj.name|length }} - -.. py:module:: {{ obj.name }} - -{% if obj.docstring %} -.. autoapi-nested-parse:: - - {{ obj.docstring|indent(3) }} - -{% endif %} - -{% block subpackages %} -{% set visible_subpackages = obj.subpackages|selectattr("display")|list %} -{% if visible_subpackages %} -Subpackages ------------ -.. toctree:: - :titlesonly: - :maxdepth: 1 - -{% for subpackage in visible_subpackages %} - {{ subpackage.short_name }}/index.rst -{% endfor %} - - -{% endif %} -{% endblock %} -{% block submodules %} -{% set visible_submodules = obj.submodules|selectattr("display")|list %} -{% if visible_submodules %} -Submodules ----------- -.. toctree:: - :titlesonly: - :maxdepth: 1 - -{% for submodule in visible_submodules %} - {{ submodule.short_name }}/index.rst -{% endfor %} - - -{% endif %} -{% endblock %} -{% block content %} -{% if obj.all is not none %} -{% set visible_children = obj.children|selectattr("short_name", "in", obj.all)|list %} -{% elif obj.type is equalto("package") %} -{% set visible_children = obj.children|selectattr("display")|list %} -{% else %} -{% set visible_children = obj.children|selectattr("display")|rejectattr("imported")|list %} -{% endif %} -{% if visible_children %} -{{ obj.type|title }} Contents -{{ "-" * obj.type|length }}--------- - -{% set visible_classes = visible_children|selectattr("type", "equalto", "class")|list %} -{% set visible_functions = visible_children|selectattr("type", "equalto", "function")|list %} -{% set visible_attributes = visible_children|selectattr("type", "equalto", "data")|list %} -{% if "show-module-summary" in autoapi_options and (visible_classes or visible_functions) %} -{% block classes scoped %} -{% if visible_classes %} -Classes -~~~~~~~ - -.. autoapisummary:: - -{% for klass in visible_classes %} - {{ klass.id }} -{% endfor %} - - -{% endif %} -{% endblock %} - -{% block functions scoped %} -{% if visible_functions %} -Functions -~~~~~~~~~ - -.. autoapisummary:: - -{% for function in visible_functions %} - {{ function.id }} -{% endfor %} - - -{% endif %} -{% endblock %} - -{% block attributes scoped %} -{% if visible_attributes %} -Attributes -~~~~~~~~~~ - -.. autoapisummary:: - -{% for attribute in visible_attributes %} - {{ attribute.id }} -{% endfor %} - - -{% endif %} -{% endblock %} -{% endif %} -{% for obj_item in visible_children %} -{{ obj_item.render()|indent(0) }} -{% endfor %} -{% endif %} -{% endblock %} diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 0000000000..eac2eabbe8 --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,12 @@ +--- +title: Changelog +description: Learn what the latest changes are! +hide: + - navigation +--- + +!!! warning + Major and minor releases also include the changes specified in prior development releases. + + +--8<-- "CHANGELOG.md" diff --git a/docs/changelog/index.md b/docs/changelog/index.md deleted file mode 100644 index 45822fff0a..0000000000 --- a/docs/changelog/index.md +++ /dev/null @@ -1,11 +0,0 @@ -# Changelog - -```{attention} -Major and minor releases also include the changes specified in prior development releases. -``` - -```{towncrier-draft-entries} Unreleased changes -``` - -```{include} ../../CHANGELOG.md -``` diff --git a/docs/conf.py b/docs/conf.py deleted file mode 100644 index 73844e5c08..0000000000 --- a/docs/conf.py +++ /dev/null @@ -1,145 +0,0 @@ -# -*- coding: utf-8 -*- -# 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. -"""Configuration file for the Sphinx documentation builder.""" -import os -import pathlib -import re -import types - -# -- Project information ----------------------------------------------------- - -with open(os.path.join("..", "hikari", "_about.py")) as fp: - code = fp.read() - -token_pattern = re.compile(r"^__(?P\w+)?__.*=\s*(?P(?:'{3}|\"{3}|'|\"))(?P.*?)(?P=quote)", re.M) - -groups = {} - -for match in token_pattern.finditer(code): - group = match.groupdict() - groups[group["key"]] = group["value"] - -metadata = types.SimpleNamespace(**groups) - -project = "hikari" -copyright = metadata.copyright -author = metadata.author -release = version = metadata.version - -PROJECT_ROOT_DIR = pathlib.Path(__file__).parents[1].resolve() - - -# -- General configuration --------------------------------------------------- - -extensions = [ - # Sphinx own extensions - "sphinx.ext.autosummary", - "sphinx.ext.autodoc", - "sphinx.ext.intersphinx", - "sphinx.ext.viewcode", - "sphinx.ext.mathjax", - # Our extensions - "myst_parser", - "sphinxext.opengraph", - "sphinx_copybutton", - "sphinxcontrib.towncrier.ext", -] - -if os.getenv("SKIP_REFERENCE_DOCS") is None: - extensions.extend( - ( - "autoapi.extension", - "numpydoc", - ) - ) - - -templates_path = ["_templates"] -exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"] - -default_role = "py:obj" - -# -- HTML output -------------------------------------------------------------- - -html_theme = "furo" -html_favicon = "https://www.hikari-py.dev/logo.png" -html_static_path = ["_static"] -html_css_files = ["extra.css"] - -# -- OpenGraph ---------------------------------------------------------------- - -ogp_site_url = "https://docs.hikari-py.dev" -ogp_image = "https://www.hikari-py.dev/logo.png" - -ogp_custom_meta_tags = [ - '', -] - -# -- AutoAPI options ---------------------------------------------------------- - -autoapi_root = "reference" -autoapi_dirs = ["../hikari"] -autoapi_ignore = ["__main__.py"] - -autoapi_options = ["members", "show-inheritance"] -autoapi_template_dir = "_templates" - -autoapi_add_toctree_entry = False -autoapi_keep_files = True -autoapi_member_order = "groupwise" - -# -- AutoDoc options ---------------------------------------------------------- - -autodoc_typehints = "none" # NumpyDoc will do it for us. We just want to remove them from the signature too -autodoc_preserve_defaults = True - -# -- NumpyDoc options --------------------------------------------------------- - -numpydoc_class_members_toctree = True -numpydoc_show_class_members = False -numpydoc_xref_param_type = True -numpydoc_validation_checks = { - "all", - # Under here are all disabled checks - "GL08", # Missing docstring - "GL06", # Unknown section -} - -# -- Intersphinx options ------------------------------------------------------ - -intersphinx_mapping = { - "python": ("https://docs.python.org/3", None), - "aiohttp": ("https://docs.aiohttp.org/en/stable", None), - "attrs": ("https://www.attrs.org/en/stable/", None), - "multidict": ("https://multidict.aio-libs.org/en/stable/", None), - "yarl": ("https://yarl.aio-libs.org/en/stable/", None), -} - -# -- MyST --------------------------------------------------------------------- - -myst_heading_anchors = 3 - -# -- Towncrier ---------------------------------------------------------------- - -towncrier_draft_autoversion_mode = "draft" -towncrier_draft_include_empty = True -towncrier_draft_working_directory = PROJECT_ROOT_DIR diff --git a/docs/gen_ref_pages.py b/docs/gen_ref_pages.py new file mode 100644 index 0000000000..3d0f0318fd --- /dev/null +++ b/docs/gen_ref_pages.py @@ -0,0 +1,56 @@ +"""Generate the code reference pages. + +Based on https://mkdocstrings.github.io/recipes/#generate-pages-on-the-fly +""" + +import pathlib + +import mkdocs_gen_files + +nav = mkdocs_gen_files.Nav() + +for path in sorted(pathlib.Path("hikari").rglob("*.py")): + module_path = path.relative_to(".").with_suffix("") + doc_path = path.relative_to(".").with_suffix(".md") + full_doc_path = pathlib.Path("reference", doc_path) + + parts = tuple(module_path.parts) + + # Ignore the internals module + if "internal" in parts: + continue + elif parts[-1] == "__init__": + parts = parts[:-1] + # Make the __init__.py the index page of the module + doc_path = doc_path.with_name("index.md") + full_doc_path = full_doc_path.with_name("index.md") + + # Ignore dunder and private modules + elif parts[-1].startswith("_"): + continue + + nav[parts] = doc_path.as_posix() + + # We could probably use some sort of template file for this if needed + with mkdocs_gen_files.open(full_doc_path, "w") as fd: + full_name = ".".join(parts) + fd.write( + "---\n" + f"title: `{full_name}`\n" + f"description: {full_name} - API reference\n" + "---\n" + f"# `{full_name}`\n" + f"::: {full_name}\n" + ) + + mkdocs_gen_files.set_edit_path(full_doc_path, pathlib.Path("..", path)) + +with mkdocs_gen_files.open("reference/summary.md", "w") as nav_file: + for item in nav.items(): + path = pathlib.Path(item.filename).with_suffix("") + + if path.name == "index": + path = path.parent + + full_name = ".".join(path.parts) + nav_file.write(" " * item.level + f"* [{full_name}]({item.filename})\n") diff --git a/docs/index.md b/docs/index.md index 62e7c6438d..1751f6df81 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,12 +1,8 @@ -# Welcome! +--- +title: Home +description: hikari documentation +hide: + - navigation +--- -```{include} ../README.md -``` - -```{toctree} -:titlesonly: -:maxdepth: 1 - -API Reference -/changelog/index -``` +--8<-- "README.md" diff --git a/docs/logo.png b/docs/logo.png new file mode 100644 index 0000000000..807782f703 Binary files /dev/null and b/docs/logo.png differ diff --git a/hikari/__init__.py b/hikari/__init__.py index c4ae3280e5..bc8738477a 100644 --- a/hikari/__init__.py +++ b/hikari/__init__.py @@ -22,9 +22,9 @@ # SOFTWARE. """A sane Python framework for writing modern Discord bots. -To get started, you will want to initialize an instance of `hikari.impl.gateway_bot.GatewayBot` -for writing a gateway based bot, `hikari.impl.rest_bot.RESTBot` for a REST based bot, -or `hikari.impl.rest.RESTApp` if you only need to use the REST API. +To get started, you will want to initialize an instance of [`hikari.impl.gateway_bot.GatewayBot`][] +for writing a gateway based bot, [`hikari.impl.rest_bot.RESTBot`][] for a REST based bot, +or [`hikari.impl.rest.RESTApp`][] if you only need to use the REST API. """ from __future__ import annotations diff --git a/hikari/api/cache.py b/hikari/api/cache.py index 643b262b7f..5c3f71c594 100644 --- a/hikari/api/cache.py +++ b/hikari/api/cache.py @@ -48,7 +48,7 @@ class CacheView(typing.Mapping[_KeyT, _ValueT], abc.ABC): """Interface describing an immutable snapshot view of part of a cache. - This can be treated as a normal `typing.Mapping` but with some special methods. + This can be treated as a normal [`typing.Mapping`][] but with some special methods. """ __slots__: typing.Sequence[str] = () @@ -102,7 +102,7 @@ def get_dm_channel_id( ------- typing.Optional[hikari.snowflakes.Snowflake] ID of the DM channel which was found cached for the supplied user or - `None`. + [`None`][]. """ @abc.abstractmethod @@ -129,7 +129,7 @@ def get_emoji( Returns ------- typing.Optional[hikari.emojis.KnownCustomEmoji] - The object of the emoji that was found in the cache or `None`. + The object of the emoji that was found in the cache or [`None`][]. """ @abc.abstractmethod @@ -175,7 +175,7 @@ def get_sticker( Returns ------- typing.Optional[hikari.stickers.GuildSticker] - The object of the sticker that was found in the cache or `None`. + The object of the sticker that was found in the cache or [`None`][]. """ @abc.abstractmethod @@ -212,11 +212,11 @@ def get_guild( ) -> typing.Optional[guilds.GatewayGuild]: """Get a guild from the cache. - .. warning:: + !!! warning This will return a guild regardless of whether it is available or - not. To only query available guilds, use `get_available_guild` + not. To only query available guilds, use [`hikari.api.cache.Cache.get_available_guild`][] instead. Likewise, to only query unavailable guilds, use - `get_unavailable_guild`. + [`hikari.api.cache.Cache.get_unavailable_guild`][]. Parameters ---------- @@ -226,7 +226,7 @@ def get_guild( Returns ------- typing.Optional[hikari.guilds.GatewayGuild] - The object of the guild if found, else `None`. + The object of the guild if found, else [`None`][]. """ @abc.abstractmethod @@ -243,17 +243,17 @@ def get_available_guild( Returns ------- typing.Optional[hikari.guilds.GatewayGuild] - The object of the guild if found, else `None`. + The object of the guild if found, else [`None`][]. """ @abc.abstractmethod def get_unavailable_guild( self, guild: snowflakes.SnowflakeishOr[guilds.PartialGuild], / ) -> typing.Optional[guilds.GatewayGuild]: - """Get the object of a unavailable guild from the cache. + """Get the object of an unavailable guild from the cache. - .. note:: - Unlike `Cache.get_available_guild`, the objects returned by this + !!! note + Unlike [`hikari.api.cache.Cache.get_available_guild`][], the objects returned by this method will likely be out of date and inaccurate as they are considered unavailable, meaning that we are not receiving gateway events for this guild. @@ -266,7 +266,7 @@ def get_unavailable_guild( Returns ------- typing.Optional[hikari.guilds.GatewayGuild] - The object of the guild if found, else `None`. + The object of the guild if found, else [`None`][]. """ @abc.abstractmethod @@ -293,8 +293,8 @@ def get_available_guilds_view(self) -> CacheView[snowflakes.Snowflake, guilds.Ga def get_unavailable_guilds_view(self) -> CacheView[snowflakes.Snowflake, guilds.GatewayGuild]: """Get a view of the unavailable guild objects in the cache. - .. note:: - Unlike `Cache.get_available_guilds_view`, the objects returned by + !!! note + Unlike [`hikari.api.cache.Cache.get_available_guilds_view`][], the objects returned by this method will likely be out of date and inaccurate as they are considered unavailable, meaning that we are not receiving gateway events for this guild. @@ -320,7 +320,7 @@ def get_guild_channel( ------- typing.Optional[hikari.channels.PermissibleGuildChannel] The object of the guild channel that was found in the cache or - `None`. + [`None`][]. """ @abc.abstractmethod @@ -367,7 +367,7 @@ def get_thread( ------- typing.Optional[hikari.channels.GuildThreadChannel] The object of the thread that was found in the cache - or `None`. + or [`None`][]. """ @abc.abstractmethod @@ -434,7 +434,7 @@ def get_invite(self, code: typing.Union[invites.InviteCode, str], /) -> typing.O Returns ------- typing.Optional[hikari.invites.InviteWithMetadata] - The object of the invite that was found in the cache or `None`. + The object of the invite that was found in the cache or [`None`][]. """ @abc.abstractmethod @@ -496,7 +496,7 @@ def get_me(self) -> typing.Optional[users.OwnUser]: Returns ------- typing.Optional[hikari.users.OwnUser] - The own user object that was found in the cache, else `None`. + The own user object that was found in the cache, else [`None`][]. """ @abc.abstractmethod @@ -518,7 +518,7 @@ def get_member( Returns ------- typing.Optional[hikari.guilds.Member] - The object of the member found in the cache, else `None`. + The object of the member found in the cache, else [`None`][]. """ @abc.abstractmethod @@ -563,7 +563,7 @@ def get_message( Returns ------- typing.Optional[hikari.messages.Message] - The object of the message found in the cache or `None`. + The object of the message found in the cache or [`None`][]. """ @abc.abstractmethod @@ -596,7 +596,7 @@ def get_presence( ------- typing.Optional[hikari.presences.MemberPresence] The object of the presence that was found in the cache or - `None`. + [`None`][]. """ @abc.abstractmethod @@ -642,7 +642,7 @@ def get_role(self, role: snowflakes.SnowflakeishOr[guilds.PartialRole], /) -> ty Returns ------- typing.Optional[hikari.guilds.Role] - The object of the role found in the cache or `None`. + The object of the role found in the cache or [`None`][]. """ @abc.abstractmethod @@ -686,7 +686,7 @@ def get_user(self, user: snowflakes.SnowflakeishOr[users.PartialUser], /) -> typ ------- typing.Optional[hikari.users.User] The object of the user that was found in the cache, else - `None`. + [`None`][]. """ @abc.abstractmethod @@ -719,7 +719,7 @@ def get_voice_state( ------- typing.Optional[hikari.voices.VoiceState] The object of the voice state that was found in the cache, or - `None`. + [`None`][]. """ @abc.abstractmethod @@ -816,7 +816,7 @@ def delete_dm_channel_id( ------- typing.Optional[hikari.snowflakes.Snowflake] The DM channel ID which was removed from the cache if found, else - `None`. + [`None`][]. """ @abc.abstractmethod @@ -840,7 +840,7 @@ def set_dm_channel_id( def clear_emojis(self) -> CacheView[snowflakes.Snowflake, emojis.KnownCustomEmoji]: """Remove all the known custom emoji objects from the cache. - .. note:: + !!! note This will skip emojis that are being kept alive by a reference on a presence entry. @@ -857,7 +857,7 @@ def clear_emojis_for_guild( ) -> CacheView[snowflakes.Snowflake, emojis.KnownCustomEmoji]: """Remove the known custom emoji objects cached for a specific guild. - .. note:: + !!! note This will skip emojis that are being kept alive by a reference on a presence entry. @@ -879,7 +879,7 @@ def delete_emoji( ) -> typing.Optional[emojis.KnownCustomEmoji]: """Remove a known custom emoji from the cache. - .. note:: + !!! note This will not delete emojis that are being kept alive by a reference on a presence entry. @@ -892,7 +892,7 @@ def delete_emoji( ------- typing.Optional[hikari.emojis.KnownCustomEmoji] The object of the emoji that was removed from the cache or - `None`. + [`None`][]. """ @abc.abstractmethod @@ -919,16 +919,16 @@ def update_emoji( Returns ------- typing.Tuple[typing.Optional[hikari.emojis.KnownCustomEmoji], typing.Optional[hikari.emojis.KnownCustomEmoji]] - A tuple of the old cached emoji object if found (else `None`) + A tuple of the old cached emoji object if found (else [`None`][]) and the new cached emoji object if it could be cached (else - `None`). + [`None`][]). """ @abc.abstractmethod def clear_stickers(self) -> CacheView[snowflakes.Snowflake, stickers.GuildSticker]: """Remove all the sticker objects from the cache. - .. note:: + !!! note This will skip stickers that are being kept alive by a reference. Returns @@ -944,14 +944,14 @@ def clear_stickers_for_guild( ) -> CacheView[snowflakes.Snowflake, stickers.GuildSticker]: """Remove the known custom emoji objects cached for a specific guild. + !!! note + This will skip stickers that are being kept alive by a reference. + Parameters ---------- guild : hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild] Object or ID of the guild to remove the cached sticker objects for. - .. note:: - This will skip stickers that are being kept alive by a reference. - Returns ------- CacheView[hikari.snowflakes.Snowflake, hikari.stickers.GuildSticker] @@ -965,7 +965,7 @@ def delete_sticker( ) -> typing.Optional[stickers.GuildSticker]: """Remove a sticker from the cache. - .. note:: + !!! note This will not delete stickers that are being kept alive by a reference. Parameters @@ -977,7 +977,7 @@ def delete_sticker( ------- typing.Optional[hikari.stickers.GuildSticker] The object of the sticker that was removed from the cache or - `None`. + [`None`][]. """ @abc.abstractmethod @@ -1016,7 +1016,7 @@ def delete_guild( ------- typing.Optional[hikari.guilds.GatewayGuild] The object of the guild that was removed from the cache, will be - `None` if not found. + [`None`][] if not found. """ @abc.abstractmethod @@ -1057,9 +1057,9 @@ def update_guild( Returns ------- typing.Tuple[typing.Optional[hikari.guilds.GatewayGuild], typing.Optional[hikari.guilds.GatewayGuild]] - A tuple of the old cached guild object if found (else `None`) + A tuple of the old cached guild object if found (else [`None`][]) and the object of the guild that was added to the cache if it could - be added (else `None`). + be added (else [`None`][]). """ @abc.abstractmethod @@ -1106,7 +1106,7 @@ def delete_guild_channel( ------- typing.Optional[hikari.channels.PermissibleGuildChannel] The object of the guild channel that was removed from the cache if - found, else `None`. + found, else [`None`][]. """ @abc.abstractmethod @@ -1135,9 +1135,9 @@ def update_guild_channel( Returns ------- typing.Tuple[typing.Optional[hikari.channels.PermissibleGuildChannel], typing.Optional[hikari.channels.PermissibleGuildChannel]] - A tuple of the old cached guild channel if found (else `None`) + A tuple of the old cached guild channel if found (else [`None`][]) and the new cached guild channel if it could be cached - (else `None`). + (else [`None`][]). """ # noqa: E501 - Line too long @abc.abstractmethod @@ -1207,7 +1207,7 @@ def delete_thread( ------- typing.Optional[hikari.channels.GuildThreadChannel] The object of the thread that was removed from the cache if - found, else `None`. + found, else [`None`][]. """ @abc.abstractmethod @@ -1234,9 +1234,9 @@ def update_thread( Returns ------- typing.Tuple[typing.Optional[hikari.channels.GuildThreadChannel], typing.Optional[hikari.channels.GuildThreadChannel]] - A tuple of the old cached thread channel if found (else `None`) + A tuple of the old cached thread channel if found (else [`None`][]) and the new cached thread channel if it could be cached - (else `None`). + (else [`None`][]). """ @abc.abstractmethod @@ -1306,7 +1306,7 @@ def delete_invite( ------- typing.Optional[hikari.invites.InviteWithMetadata] The object of the invite that was removed from the cache if found, - else `None`. + else [`None`][]. """ @abc.abstractmethod @@ -1334,8 +1334,8 @@ def update_invite( ------- typing.Tuple[typing.Optional[hikari.invites.InviteWithMetadata], typing.Optional[hikari.invites.InviteWithMetadata]] A tuple of the old cached invite object if found (else - `None`) and the new cached invite object if it could be - cached (else `None`). + [`None`][]) and the new cached invite object if it could be + cached (else [`None`][]). """ @abc.abstractmethod @@ -1346,7 +1346,7 @@ def delete_me(self) -> typing.Optional[users.OwnUser]: ------- typing.Optional[hikari.users.OwnUser] The own user object that was removed from the cache if found, - else `None`. + else [`None`][]. """ @abc.abstractmethod @@ -1374,8 +1374,8 @@ def update_me( ------- typing.Tuple[typing.Optional[hikari.users.OwnUser], typing.Optional[hikari.users.OwnUser]] A tuple of the old cached own user object if found (else - `None`) and the new cached own user object if it could be - cached, else `None`. + [`None`][]) and the new cached own user object if it could be + cached, else [`None`][]. """ @abc.abstractmethod @@ -1395,7 +1395,7 @@ def clear_members_for_guild( ) -> CacheView[snowflakes.Snowflake, guilds.Member]: """Remove the members for a specific guild from the cache. - .. note:: + !!! note This will skip members that are being referenced by other entries in the cache; a matching voice state will keep a member entry alive. @@ -1420,7 +1420,7 @@ def delete_member( ) -> typing.Optional[guilds.Member]: """Remove a member object from the cache. - .. note:: + !!! note You cannot delete a member entry that's being referenced by other entries in the cache; a matching voice state will keep a member entry alive. @@ -1436,7 +1436,7 @@ def delete_member( ------- typing.Optional[hikari.guilds.Member] The object of the member that was removed from the cache if found, - else `None`. + else [`None`][]. """ @abc.abstractmethod @@ -1463,9 +1463,9 @@ def update_member( Returns ------- typing.Tuple[typing.Optional[hikari.guilds.Member], typing.Optional[hikari.guilds.Member]] - A tuple of the old cached member object if found (else `None`) + A tuple of the old cached member object if found (else [`None`][]) and the new cached member object if it could be cached (else - `None`). + [`None`][]). """ @abc.abstractmethod @@ -1519,7 +1519,7 @@ def delete_presence( ------- typing.Optional[hikari.presences.MemberPresence] The object of the presence that was removed from the cache if found, - else `None`. + else [`None`][]. """ @abc.abstractmethod @@ -1546,9 +1546,9 @@ def update_presence( Returns ------- typing.Tuple[typing.Optional[hikari.presences.MemberPresence], typing.Optional[hikari.presences.MemberPresence]] - A tuple of the old cached invite object if found (else `None` + A tuple of the old cached invite object if found (else [`None`][] and the new cached invite object if it could be cached ( else - `None`). + [`None`][]). """ @abc.abstractmethod @@ -1593,7 +1593,7 @@ def delete_role(self, role: snowflakes.SnowflakeishOr[guilds.PartialRole], /) -> ------- typing.Optional[hikari.guilds.Role] The object of the role that was removed from the cache if found, - else `None`. + else [`None`][]. """ @abc.abstractmethod @@ -1620,9 +1620,9 @@ def update_role( Returns ------- typing.Tuple[typing.Optional[hikari.guilds.Role], typing.Optional[hikari.guilds.Role]] - A tuple of the old cached role object if found (else `None` + A tuple of the old cached role object if found (else [`None`][] and the new cached role object if it could be cached (else - `None`). + [`None`][]). """ @abc.abstractmethod @@ -1697,7 +1697,7 @@ def delete_voice_state( ------- typing.Optional[hikari.voices.VoiceState] The object of the voice state that was removed from the cache if - found, else `None`. + found, else [`None`][]. """ @abc.abstractmethod @@ -1724,9 +1724,9 @@ def update_voice_state( Returns ------- typing.Tuple[typing.Optional[hikari.voices.VoiceState], typing.Optional[hikari.voices.VoiceState]] - A tuple of the old cached voice state if found (else `None`) + A tuple of the old cached voice state if found (else [`None`][]) and the new cached voice state object if it could be cached - (else `None`). + (else [`None`][]). """ @abc.abstractmethod @@ -1754,7 +1754,7 @@ def delete_message( ------- typing.Optional[hikari.messages.Message] The object of the message that was removed from the cache if found, - else `None`. + else [`None`][]. """ @abc.abstractmethod @@ -1781,7 +1781,7 @@ def update_message( Returns ------- typing.Tuple[typing.Optional[hikari.messages.Message], typing.Optional[hikari.messages.Message]] - A tuple of the old cached message object if found (else `None`) + A tuple of the old cached message object if found (else [`None`][]) and the new cached message object if it could be cached (else - `None`). + [`None`][]). """ diff --git a/hikari/api/config.py b/hikari/api/config.py index 8907783bfc..69ca0be41c 100644 --- a/hikari/api/config.py +++ b/hikari/api/config.py @@ -107,7 +107,7 @@ class ProxySettings(abc.ABC): def url(self) -> typing.Union[None, str]: """Proxy URL to use. - If this is `None` then no explicit proxy is being used. + If this is [`None`][] then no explicit proxy is being used. """ @property @@ -115,13 +115,13 @@ def url(self) -> typing.Union[None, str]: 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 + 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. + If [`False`][], then this information is instead ignored. - .. note:: + !!! note For more details of using `netrc`, visit: https://www.gnu.org/software/inetutils/manual/html_node/The-_002enetrc-file.html """ @@ -137,11 +137,11 @@ class HTTPSettings(abc.ABC): def max_redirects(self) -> typing.Optional[int]: """Behavior for handling redirect HTTP responses. - If a `int`, allow following redirects from `3xx` 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. + If [`None`][], then disallow any redirects. The default is to disallow this behavior for security reasons. @@ -149,7 +149,7 @@ def max_redirects(self) -> typing.Optional[int]: future where you need to enable this if Discord change their URL without warning. - .. note:: + !!! note This will only apply to the REST API. WebSockets remain unaffected by any value set here. """ @@ -159,24 +159,24 @@ def max_redirects(self) -> typing.Optional[int]: def ssl(self) -> ssl_.SSLContext: """SSL context to use. - This may be assigned a `bool` or an `ssl.SSLContext` object. + This may be assigned a [`bool`][] or an [`ssl.SSLContext`][] object. - If assigned to `True`, a default SSL context is generated by + 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 + 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. + If an instance of [`ssl.SSLContext`][], then this context will be used. - .. warning:: + !!! 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:: + !!! 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 @@ -207,6 +207,4 @@ def only_my_member(self) -> bool: Useful when only the bot member is required (eg. permission checks). This will have no effect if the members cache is not enabled. - - Defaults to `False`. """ diff --git a/hikari/api/entity_factory.py b/hikari/api/entity_factory.py index a6ff73c438..fdbf1c6d45 100644 --- a/hikari/api/entity_factory.py +++ b/hikari/api/entity_factory.py @@ -60,8 +60,8 @@ class GatewayGuildDefinition(abc.ABC): """Structure for handling entities within guild create and update events. - .. warning:: - The methods on this class may raise `LookupError` if called + !!! warning + The methods on this class may raise [`LookupError`][] if called when the relevant resource isn't available in the inner payload. """ @@ -92,7 +92,7 @@ def guild(self) -> guild_models.GatewayGuild: def members(self) -> typing.Mapping[snowflakes.Snowflake, guild_models.Member]: """Get a mapping of user IDs to the members that belong to the guild. - .. note:: + !!! note This may be a partial mapping of members in the guild. """ @@ -100,7 +100,7 @@ def members(self) -> typing.Mapping[snowflakes.Snowflake, guild_models.Member]: def presences(self) -> typing.Mapping[snowflakes.Snowflake, presence_models.MemberPresence]: """Get a mapping of user IDs to the presences that are active in the guild. - .. note:: + !!! note This may be a partial mapping of presences active in the guild. """ @@ -337,7 +337,7 @@ def deserialize_audit_log_entry( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload. """ @@ -466,7 +466,7 @@ def deserialize_guild_category( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload. """ @@ -501,7 +501,7 @@ def deserialize_guild_text_channel( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload. """ @@ -536,7 +536,7 @@ def deserialize_guild_news_channel( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload. """ @@ -571,7 +571,7 @@ def deserialize_guild_voice_channel( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload. """ @@ -606,7 +606,7 @@ def deserialize_guild_stage_channel( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload. """ @@ -641,7 +641,7 @@ def deserialize_guild_forum_channel( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload. """ @@ -680,8 +680,8 @@ def deserialize_thread_member( ID of the thread this member belongs to. This will be prioritised over `"id"` in the payload when passed. - .. note:: - `thread_id` currently only covers the gateway GUILD_CREATE event + !!! note + `thread_id` currently only covers the gateway `GUILD_CREATE` event where the field are is included in the thread member's payload. Returns @@ -692,7 +692,7 @@ def deserialize_thread_member( Raises ------ KeyError - If `thread_id` or `user_id` is left as `hikari.undefined.UNDEFINED` + If `thread_id` is left as [`hikari.undefined.UNDEFINED`][] when the relevant field isn't present in the passed payload. """ @@ -712,8 +712,8 @@ def deserialize_guild_thread( The ID of the guild this channel belongs to. If passed then this will be prioritised over `"guild_id"` in the payload. - .. note:: - `guild_id` currently only covers the gateway GUILD_CREATE event + !!! note + `guild_id` currently only covers the gateway `GUILD_CREATE` event where `"guild_id"` is not included in the channel's payload. member : hikari.undefined.UndefinedNoneOr[hikari.channels.ThreadMember] The member object for the thread. If passed then this will be @@ -727,7 +727,7 @@ def deserialize_guild_thread( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload. """ @@ -752,8 +752,8 @@ def deserialize_guild_news_thread( The ID of the guild this channel belongs to. This will be prioritised over `"guild_id"` in the payload when passed. - .. note:: - `guild_id` currently only covers the gateway GUILD_CREATE event + !!! note + `guild_id` currently only covers the gateway `GUILD_CREATE` event where `"guild_id"` is not included in the channel's payload. member : hikari.undefined.UndefinedNoneOr[hikari.channels.ThreadMember] The member object for the thread. If passed then this will be @@ -767,7 +767,7 @@ def deserialize_guild_news_thread( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload. """ @@ -792,8 +792,8 @@ def deserialize_guild_public_thread( The ID of the guild this channel belongs to. This will be prioritised over `"guild_id"` in the payload when passed. - .. note:: - `guild_id` currently only covers the gateway GUILD_CREATE event + !!! note + `guild_id` currently only covers the gateway `GUILD_CREATE` event where `"guild_id"` is not included in the channel's payload. member : hikari.undefined.UndefinedNoneOr[hikari.channels.ThreadMember] The member object for the thread. If passed then this will be @@ -807,7 +807,7 @@ def deserialize_guild_public_thread( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload. """ @@ -832,8 +832,8 @@ def deserialize_guild_private_thread( The ID of the guild this channel belongs to. This will be prioritised over `"guild_id"` in the payload when passed. - .. note:: - `guild_id` currently only covers the gateway GUILD_CREATE event + !!! note + `guild_id` currently only covers the gateway `GUILD_CREATE` event where `"guild_id"` is not included in the channel's payload. member : hikari.undefined.UndefinedNoneOr[hikari.channels.ThreadMember] The member object for the thread. If passed then this will be @@ -847,7 +847,7 @@ def deserialize_guild_private_thread( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload. """ @@ -860,7 +860,7 @@ def deserialize_channel( ) -> channel_models.PartialChannel: """Parse a raw payload from Discord into a channel object. - .. note:: + !!! note This also deserializes to thread channels. Parameters @@ -875,7 +875,7 @@ def deserialize_channel( for DM and group DM channels and will be prioritised over `"guild_id"` in the payload when passed. - This is necessary in GUILD_CREATE events, where `"guild_id"` is not + This is necessary in `GUILD_CREATE` events, where `"guild_id"` is not included in the channel's payload Returns @@ -886,7 +886,7 @@ def deserialize_channel( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload of a guild channel. hikari.errors.UnrecognisedEntityError @@ -1081,7 +1081,7 @@ def deserialize_member( ) -> guild_models.Member: """Parse a raw payload from Discord into a member object. - .. note:: + !!! note `guild_id` covers cases such as the GUILD_CREATE gateway event and GET Guild Member where `"guild_id"` is not included in the returned payload. @@ -1108,7 +1108,7 @@ def deserialize_member( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload. """ @@ -1176,7 +1176,7 @@ def deserialize_integration( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload for the payload of the integration. """ @@ -1243,13 +1243,13 @@ def deserialize_gateway_guild( ------- GatewayGuildDefinition The deserialized guild object and the internal collections as - maps of `hikari.snowflakes.Snowflake` mapping to - `hikari.channels.GuildChannel`, - `hikari.guilds.Member`, - `hikari.presences.MemberPresence`, - `hikari.guilds.Role`, - `hikari.emojis.KnownCustomEmoji`, and - `hikari.stickers.GuildSticker`. This is provided in + maps of [`hikari.snowflakes.Snowflake`][] mapping to + [`hikari.channels.GuildChannel`][], + [`hikari.guilds.Member`][], + [`hikari.presences.MemberPresence`][], + [`hikari.guilds.Role`][], + [`hikari.emojis.KnownCustomEmoji`][], and + [`hikari.stickers.GuildSticker`][]. This is provided in several components to allow separate caching and linking between entities in various relational cache implementations internally. @@ -1287,7 +1287,7 @@ def deserialize_slash_command( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload for the payload of the integration. """ @@ -1320,7 +1320,7 @@ def deserialize_context_menu_command( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload for the payload of the integration. """ @@ -1353,7 +1353,7 @@ def deserialize_command( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload for the payload of the integration. hikari.errors.UnrecognisedEntityError @@ -1460,10 +1460,10 @@ def deserialize_modal_interaction(self, payload: data_binding.JSONObject) -> mod def deserialize_interaction(self, payload: data_binding.JSONObject) -> base_interactions.PartialInteraction: """Parse a raw payload from Discord into an interaction object. - .. note:: + !!! note This isn't required to implement logic for deserializing PING interactions and if you want to unmarshal those - `EntityFactory.deserialize_partial_interaction` should be compatible. + [`hikari.api.entity_factory.EntityFactory.deserialize_partial_interaction`][] should be compatible. Parameters ---------- @@ -1673,7 +1673,7 @@ def deserialize_member_presence( ) -> presence_models.MemberPresence: """Parse a raw payload from Discord into a member presence object. - .. note:: + !!! note At the time of writing, the only place where `guild_id` will be mandatory is when parsing presences sent in a `GUILD_CREATE` event from Discord, since the `guild_id` attribute in the payload will @@ -1698,10 +1698,8 @@ def deserialize_member_presence( Raises ------ KeyError - If `guild_id` is not an attribute of the `payload` dict, and no - guild ID was passed for the `guild_id` parameter. - - If this is raised, no guild ID info was provided anywhere. + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when + `"guild_id"` is not present in the passed payload. """ ########################## @@ -1872,7 +1870,7 @@ def deserialize_voice_state( ) -> voice_models.VoiceState: """Parse a raw payload from Discord into a voice state object. - .. note:: + !!! note At the time of writing, `GUILD_CREATE` events are the only known place where neither `guild_id` nor `member` will be keys on the payload. In this case, you will need to provide the former @@ -1901,7 +1899,7 @@ def deserialize_voice_state( Raises ------ KeyError - If `guild_id` is left as `hikari.undefined.UNDEFINED` when + If `guild_id` is left as [`hikari.undefined.UNDEFINED`][] when `"guild_id"` is not present in the passed payload for the payload of the voice state. diff --git a/hikari/api/event_factory.py b/hikari/api/event_factory.py index 32515c636f..b38eab86d4 100644 --- a/hikari/api/event_factory.py +++ b/hikari/api/event_factory.py @@ -129,7 +129,7 @@ def deserialize_guild_channel_update_event( Other Parameters ---------------- old_channel : typing.Optional[hikari.channels.PermissibleGuildChannel] - The guild channel object or `None`. + The guild channel object or [`None`][]. Returns ------- @@ -347,7 +347,7 @@ def deserialize_invite_delete_event( Other Parameters ---------------- old_invite : typing.Optional[hikari.invites.InviteWithMetadata] - The invite object or `None`. + The invite object or [`None`][]. Returns ------- @@ -440,7 +440,7 @@ def deserialize_guild_update_event( Other Parameters ---------------- old_guild : typing.Optional[hikari.guilds.GatewayGuild] - The guild object or `None`. + The guild object or [`None`][]. Returns ------- @@ -468,7 +468,7 @@ def deserialize_guild_leave_event( Other Parameters ---------------- old_guild : typing.Optional[hikari.guilds.GatewayGuild] - The guild object or `None`. + The guild object or [`None`][]. Returns ------- @@ -553,7 +553,7 @@ def deserialize_guild_emojis_update_event( Other Parameters ---------------- old_emojis : typing.Optional[typing.Sequence[hikari.emojis.KnownCustomEmoji]] - The sequence of emojis or `None`. + The sequence of emojis or [`None`][]. Returns ------- @@ -581,7 +581,7 @@ def deserialize_guild_stickers_update_event( Other Parameters ---------------- old_stickers : typing.Optional[typing.Sequence[hikari.stickers.GuildSticker]] - The sequence of stickers or `None`. + The sequence of stickers or [`None`][]. Returns ------- @@ -666,7 +666,7 @@ def deserialize_presence_update_event( Other Parameters ---------------- old_presence : typing.Optional[hikari.presences.MemberPresence] - The presence object or `None`. + The presence object or [`None`][]. Returns ------- @@ -759,7 +759,7 @@ def deserialize_guild_member_update_event( Other Parameters ---------------- old_member : typing.Optional[hikari.guilds.Member] - The member object or `None`. + The member object or [`None`][]. Returns ------- @@ -787,7 +787,7 @@ def deserialize_guild_member_remove_event( Other Parameters ---------------- old_member : typing.Optional[hikari.guilds.Member] - The member object or `None`. + The member object or [`None`][]. Returns ------- @@ -838,7 +838,7 @@ def deserialize_guild_role_update_event( Other Parameters ---------------- old_role : typing.Optional[hikari.guilds.Role] - The role object or `None`. + The role object or [`None`][]. Returns ------- @@ -866,7 +866,7 @@ def deserialize_guild_role_delete_event( Other Parameters ---------------- old_role : typing.Optional[hikari.guilds.Role] - The role object or `None`. + The role object or [`None`][]. Returns ------- @@ -1060,7 +1060,7 @@ def deserialize_message_update_event( Other Parameters ---------------- old_message : typing.Optional[hikari.messages.PartialMessage] - The message object or `None`. + The message object or [`None`][]. Returns ------- @@ -1336,7 +1336,7 @@ def deserialize_own_user_update_event( Other Parameters ---------------- old_user : typing.Optional[hikari.users.OwnUser] - The OwnUser object or `None`. + The OwnUser object or [`None`][]. Returns ------- @@ -1368,7 +1368,7 @@ def deserialize_voice_state_update_event( Other Parameters ---------------- old_state : typing.Optional[hikari.voices.VoiceState] - The VoiceState object or `None`. + The VoiceState object or [`None`][]. Returns ------- diff --git a/hikari/api/event_manager.py b/hikari/api/event_manager.py index 5d66d5cd9a..f2b605aa40 100644 --- a/hikari/api/event_manager.py +++ b/hikari/api/event_manager.py @@ -50,38 +50,38 @@ class EventStream(iterators.LazyIterator[base_events.EventT], abc.ABC): """A base abstract class for all event streamers. - Unlike `hikari.iterators.LazyIterator` (which this extends), an event + Unlike [`hikari.iterators.LazyIterator`][] (which this extends), an event streamer must be started and closed. Examples -------- A streamer may either be started and closed using `with` syntax - where `EventStream.open` and `EventStream.close` are implicitly called based on - context. - - .. code-block:: python + where [`hikari.api.event_manager.EventStream.open`][] and + [`hikari.api.event_manager.EventStream.close`][] are implicitly called based on context. + ```py with EventStream(app, EventType, timeout=50) as stream: async for entry in stream: ... + ``` - A streamer may also be directly started and closed using the `EventStream.close` - and `EventStream.open`. Note that if you don't call `EventStream.close` after - opening a streamer when you're finished with it then it may queue events - events in memory indefinitely. - - .. code-block:: python + A streamer may also be directly started and closed using the [`hikari.api.event_manager.EventStream.close`][] + and [`hikari.api.event_manager.EventStream.open`][]. Note that if you don't call + [`hikari.api.event_manager.EventStream.close`][] after opening a streamer when + you're finished with it then it may queue events in memory indefinitely. + ```py stream = EventStream(app, EventType, timeout=50) await stream.open() async for event in stream: ... await stream.close() + ``` See Also -------- - LazyIterator : `hikari.iterators.LazyIterator`. + LazyIterator : [`hikari.iterators.LazyIterator`][]. """ __slots__: typing.Sequence[str] = () @@ -92,8 +92,8 @@ def close(self) -> None: If called on an already closed streamer then this will do nothing. - .. note:: - `with streamer` may be used as a short-cut for opening and + !!! note + [with streamer][] may be used as a short-cut for opening and closing a streamer. """ @@ -103,8 +103,8 @@ def open(self) -> None: If called on an already started streamer then this will do nothing. - .. note:: - `with streamer` may be used as a short-cut for opening and + !!! note + [with streamer][] may be used as a short-cut for opening and closing a stream. """ @@ -119,7 +119,7 @@ def filter( Each condition is treated as a predicate, being called with each item that this iterator would return when it is requested. - All conditions must evaluate to `True` for the item to be + All conditions must evaluate to [`True`][] for the item to be returned. If this is not met, then the item is discarded and ignored, the next matching item will be returned instead, if there is one. @@ -127,10 +127,10 @@ def filter( ---------- *predicates : typing.Union[typing.Callable[[ValueT], bool], typing.Tuple[str, typing.Any]] Predicates to invoke. These are functions that take a value and - return `True` if it is of interest, or `False` - otherwise. These may instead include 2-`tuple` objects - consisting of a `str` attribute name (nested attributes - are referred to using the ``.`` operator), and values to compare for + return [`True`][] if it is of interest, or [`False`][] + otherwise. These may instead include 2-[`tuple`][] objects + consisting of a [`str`][] attribute name (nested attributes + are referred to using the `.` operator), and values to compare for equality. This allows you to specify conditions such as `members.filter(("user.bot", True))`. **attrs : typing.Any @@ -160,7 +160,7 @@ def __exit__( class EventManager(abc.ABC): """Base interface for event manager implementations. - This is a listener of a `hikari.events.base_events.Event` object and + This is a listener of a [`hikari.events.base_events.Event`][] object and consumer of raw event payloads, and is expected to invoke one or more corresponding event listeners where appropriate. """ @@ -200,10 +200,9 @@ def dispatch(self, event: base_events.Event) -> asyncio.Future[typing.Any]: Examples -------- We can dispatch custom events by first defining a class that - derives from `hikari.events.base_events.Event`. - - .. code-block:: python + derives from [`hikari.events.base_events.Event`][]. + ```py import attrs from hikari.traits import RESTAware @@ -226,11 +225,11 @@ class EveryoneMentionedEvent(Event): channel_id: Snowflake = attrs.field() '''The channel ID.''' + ``` We can then dispatch our event as we see fit. - .. code-block:: python - + ```py from hikari.events.messages import MessageCreateEvent @bot.listen(MessageCreateEvent) @@ -244,15 +243,16 @@ async def on_message(event): ) bot.dispatch(event) + ``` This event can be listened to elsewhere by subscribing to it with - `EventManager.subscribe`. - - .. code-block:: python + [`hikari.api.event_manager.EventManager.subscribe`][]. + ```py @bot.listen(EveryoneMentionedEvent) async def on_everyone_mentioned(event): print(event.user, "just pinged everyone in", event.channel_id) + ``` Returns ------- @@ -264,11 +264,11 @@ async def on_everyone_mentioned(event): See Also -------- - Listen : `hikari.api.event_manager.EventManager.listen`. - Stream : `hikari.api.event_manager.EventManager.stream`. - Subscribe : `hikari.api.event_manager.EventManager.subscribe`. - Unsubscribe : `hikari.api.event_manager.EventManager.unsubscribe`. - Wait_for: `hikari.api.event_manager.EventManager.wait_for`. + Listen : [`hikari.api.event_manager.EventManager.listen`][]. + Stream : [`hikari.api.event_manager.EventManager.stream`][]. + Subscribe : [`hikari.api.event_manager.EventManager.subscribe`][]. + Unsubscribe : [`hikari.api.event_manager.EventManager.unsubscribe`][]. + Wait_for: [`hikari.api.event_manager.EventManager.wait_for`][]. """ # Yes, this is not generic. The reason for this is MyPy complains about @@ -284,7 +284,7 @@ def subscribe(self, event_type: typing.Type[typing.Any], callback: CallbackT[typ event_type : typing.Type[T] The event type to listen for. This will also listen for any subclasses of the given type. - `T` must be a subclass of `hikari.events.base_events.Event`. + `T` must be a subclass of [`hikari.events.base_events.Event`][]. callback Must be a coroutine function to invoke. This should consume an instance of the given event, or an instance of a valid @@ -295,22 +295,22 @@ def subscribe(self, event_type: typing.Type[typing.Any], callback: CallbackT[typ The following demonstrates subscribing a callback to message creation events. - .. code-block:: python - + ```py from hikari.events.messages import MessageCreateEvent async def on_message(event): ... bot.subscribe(MessageCreateEvent, on_message) + ``` See Also -------- - Dispatch : `hikari.api.event_manager.EventManager.dispatch`. - Listen : `hikari.api.event_manager.EventManager.listen`. - Stream : `hikari.api.event_manager.EventManager.stream`. - Unsubscribe : `hikari.api.event_manager.EventManager.unsubscribe`. - Wait_for : `hikari.api.event_manager.EventManager.wait_for`. + Dispatch : [`hikari.api.event_manager.EventManager.dispatch`][]. + Listen : [`hikari.api.event_manager.EventManager.listen`][]. + Stream : [`hikari.api.event_manager.EventManager.stream`][]. + Unsubscribe : [`hikari.api.event_manager.EventManager.unsubscribe`][]. + Wait_for : [`hikari.api.event_manager.EventManager.wait_for`][]. """ # Yes, this is not generic. The reason for this is MyPy complains about @@ -326,7 +326,7 @@ def unsubscribe(self, event_type: typing.Type[typing.Any], callback: CallbackT[t event_type : typing.Type[T] The event type to unsubscribe from. This must be the same exact type as was originally subscribed with to be removed correctly. - `T` must derive from `hikari.events.base_events.Event`. + `T` must derive from [`hikari.events.base_events.Event`][]. callback The callback to unsubscribe. @@ -335,22 +335,22 @@ def unsubscribe(self, event_type: typing.Type[typing.Any], callback: CallbackT[t The following demonstrates unsubscribing a callback from a message creation event. - .. code-block:: python - + ```py from hikari.events.messages import MessageCreateEvent async def on_message(event): ... bot.unsubscribe(MessageCreateEvent, on_message) + ``` See Also -------- - Dispatch : `hikari.api.event_manager.EventManager.dispatch`. - Listen : `hikari.api.event_manager.EventManager.listen`. - Stream : `hikari.api.event_manager.EventManager.stream`. - Subscribe : `hikari.api.event_manager.EventManager.subscribe`. - Wait_for : `hikari.api.event_manager.EventManager.wait_for`. + Dispatch : [`hikari.api.event_manager.EventManager.dispatch`][]. + Listen : [`hikari.api.event_manager.EventManager.listen`][]. + Stream : [`hikari.api.event_manager.EventManager.stream`][]. + Subscribe : [`hikari.api.event_manager.EventManager.subscribe`][]. + Wait_for : [`hikari.api.event_manager.EventManager.wait_for`][]. """ @abc.abstractmethod @@ -363,12 +363,12 @@ def get_listeners( ---------- event_type : typing.Type[T] The event type to look for. - `T` must be a subclass of `hikari.events.base_events.Event`. + `T` must be a subclass of [`hikari.events.base_events.Event`][]. polymorphic : bool - If `True`, this will also return the listeners for all the - event types `event_type` will dispatch. If `False`, then + If [`True`][], this will also return the listeners for all the + event types `event_type` will dispatch. If [`False`][], then only listeners for this class specifically are returned. The - default is `True`. + default is [`True`][]. Returns ------- @@ -391,22 +391,22 @@ def listen( The event types to subscribe to. The implementation may allow this to be undefined. If this is the case, the event type will be inferred instead from the type hints on the function signature. - `T` must be a subclass of `hikari.events.base_events.Event`. + `T` must be a subclass of [`hikari.events.base_events.Event`][]. Returns ------- typing.Callable[[T], T] A decorator for a coroutine function that passes it to - `EventManager.subscribe` before returning the function + [`hikari.api.event_manager.EventManager.subscribe`][] before returning the function reference. See Also -------- - Dispatch : `hikari.api.event_manager.EventManager.dispatch`. - Stream : `hikari.api.event_manager.EventManager.stream`. - Subscribe : `hikari.api.event_manager.EventManager.subscribe`. - Unsubscribe : `hikari.api.event_manager.EventManager.unsubscribe`. - Wait_for : `hikari.api.event_manager.EventManager.wait_for`. + Dispatch : [`hikari.api.event_manager.EventManager.dispatch`][]. + Stream : [`hikari.api.event_manager.EventManager.stream`][]. + Subscribe : [`hikari.api.event_manager.EventManager.subscribe`][]. + Unsubscribe : [`hikari.api.event_manager.EventManager.unsubscribe`][]. + Wait_for : [`hikari.api.event_manager.EventManager.wait_for`][]. """ @abc.abstractmethod @@ -419,9 +419,9 @@ def stream( ) -> EventStream[base_events.EventT]: """Return a stream iterator for the given event and sub-events. - .. warning:: - If you use `await stream.open()` to start the stream then you must - also close it with `await stream.close()` otherwise it may queue + !!! warning + If you use [await stream.open()][] to start the stream then you must + also close it with [await stream.close()][] otherwise it may queue events in memory indefinitely. Parameters @@ -431,32 +431,31 @@ def stream( this type additionally. timeout : typing.Optional[int, float] How long this streamer should wait for the next event before - ending the iteration. If `None` then this will continue + ending the iteration. If [`None`][] then this will continue until explicitly broken from. limit : typing.Optional[int] The limit for how many events this should queue at one time before - dropping extra incoming events, leave this as `None` for + dropping extra incoming events, leave this as [`None`][] for the cache size to be unlimited. Returns ------- EventStream[hikari.events.base_events.Event] The async iterator to handle streamed events. This must be started - with `with stream:` or `stream.open()` before - asynchronously iterating over it. + with `with stream:` or [`stream.open`][hikari.api.event_manager.EventStream.open] + before asynchronously iterating over it. Examples -------- - .. code-block:: python - + ```py with bot.stream(events.ReactionAddEvent, timeout=30).filter(("message_id", message.id)) as stream: async for user_id in stream.map("user_id").limit(50): ... + ``` or using `open()` and `close()` - .. code-block:: python - + ```py stream = bot.stream(events.ReactionAddEvent, timeout=30).filter(("message_id", message.id)) stream.open() @@ -464,14 +463,15 @@ def stream( ... stream.close() + ``` See Also -------- - Dispatch : `hikari.api.event_manager.EventManager.dispatch`. - Listen : `hikari.api.event_manager.EventManager.listen`. - Subscribe : `hikari.api.event_manager.EventManager.subscribe`. - Unsubscribe : `hikari.api.event_manager.EventManager.unsubscribe`. - Wait_for : `hikari.api.event_manager.EventManager.wait_for`. + Dispatch : [`hikari.api.event_manager.EventManager.dispatch`][]. + Listen : [`hikari.api.event_manager.EventManager.listen`][]. + Subscribe : [`hikari.api.event_manager.EventManager.subscribe`][]. + Unsubscribe : [`hikari.api.event_manager.EventManager.unsubscribe`][]. + Wait_for : [`hikari.api.event_manager.EventManager.wait_for`][]. """ @abc.abstractmethod @@ -484,7 +484,7 @@ async def wait_for( ) -> base_events.EventT: """Wait for a given event to occur once, then return the event. - .. warning:: + !!! warning Async predicates are not supported. Parameters @@ -494,14 +494,14 @@ async def wait_for( this type additionally. predicate A function taking the event as the single parameter. - This should return `True` if the event is one you want to - return, or `False` if the event should not be returned. - If left as `None` (the default), then the first matching event type + This should return [`True`][] if the event is one you want to + return, or [`False`][] if the event should not be returned. + If left as [`None`][] (the default), then the first matching event type that the bot receives (or any subtype) will be the one returned. timeout : typing.Union[float, int, None] - The amount of time to wait before raising an `asyncio.TimeoutError` + The amount of time to wait before raising an [`asyncio.TimeoutError`][] and giving up instead. This is measured in seconds. If - `None`, then no timeout will be waited for (no timeout can + [`None`][], then no timeout will be waited for (no timeout can result in "leaking" of coroutines that never complete if called in an uncontrolled way, so is not recommended). @@ -513,14 +513,14 @@ async def wait_for( Raises ------ asyncio.TimeoutError - If the timeout is not `None` and is reached before an - event is received that the predicate returns `True` for. + If the timeout is not [`None`][] and is reached before an + event is received that the predicate returns [`True`][] for. See Also -------- - Dispatch : `hikari.api.event_manager.EventManager.dispatch`. - Listen : `hikari.api.event_manager.EventManager.listen`. - Stream : `hikari.api.event_manager.EventManager.stream`. - Subscribe : `hikari.api.event_manager.EventManager.subscribe`. - Unsubscribe : `hikari.api.event_manager.EventManager.unsubscribe`. + Dispatch : [`hikari.api.event_manager.EventManager.dispatch`][]. + Listen : [`hikari.api.event_manager.EventManager.listen`][]. + Stream : [`hikari.api.event_manager.EventManager.stream`][]. + Subscribe : [`hikari.api.event_manager.EventManager.subscribe`][]. + Unsubscribe : [`hikari.api.event_manager.EventManager.unsubscribe`][]. """ diff --git a/hikari/api/interaction_server.py b/hikari/api/interaction_server.py index 9f2067749c..0f36dbe6f3 100644 --- a/hikari/api/interaction_server.py +++ b/hikari/api/interaction_server.py @@ -51,20 +51,20 @@ """Type hint of a Interaction server's listener callback. This should be an async callback which takes in one positional argument which -subclasses `hikari.interactions.base_interactions.PartialInteraction` and may return an -instance of the relevant `hikari.api.special_endpoints.InteractionResponseBuilder` +subclasses [`hikari.interactions.base_interactions.PartialInteraction`][] and may return an +instance of the relevant [`hikari.api.special_endpoints.InteractionResponseBuilder`][] subclass for the provided interaction type which will instruct the server on how to respond. -.. note:: +!!! note For the standard implementations of - `hikari.api.special_endpoints.InteractionResponseBuilder` see - `hikari.impl.special_endpoints`. + [`hikari.api.special_endpoints.InteractionResponseBuilder`][] see + [`hikari.impl.special_endpoints`][]. """ class Response(typing.Protocol): - """Protocol of the data returned by `InteractionServer.on_interaction`. + """Protocol of the data returned by [`hikari.api.interaction_server.InteractionServer.on_interaction`][]. This is used to instruct lower-level REST server logic on how it should respond. @@ -178,7 +178,7 @@ def get_listener( ------- typing.Optional[ListenersT[hikari.interactions.base_interactions.PartialInteraction, hikari.api.special_endpoints.InteractionResponseBuilder] The callback registered for the provided interaction type if found, - else `None`. + else [`None`][]. """ # noqa: E501 - Line too long @typing.overload @@ -245,7 +245,7 @@ def set_listener( interaction_type : typing.Type[hikari.interactions.base_interactions.PartialInteraction] The type of interaction this listener should be registered for. listener : typing.Optional[ListenerT[hikari.interactions.base_interactions.PartialInteraction, hikari.api.special_endpoints.InteractionResponseBuilder]] - The asynchronous listener callback to set or `None` to unset the previous listener. + The asynchronous listener callback to set or [`None`][] to unset the previous listener. An asynchronous listener can be either a normal coroutine or an async generator which should yield exactly once. This allows @@ -256,11 +256,9 @@ def set_listener( ---------------- replace : bool Whether this call should replace the previously set listener or not. - This call will raise a `ValueError` if set to `False` - when a listener is already set. Raises ------ TypeError - If `replace` is `False` when a listener is already set. + If `replace` is [`False`][] when a listener is already set. """ # noqa: E501 - Line too long diff --git a/hikari/api/rest.py b/hikari/api/rest.py index 4fb138f05e..4c79af053b 100644 --- a/hikari/api/rest.py +++ b/hikari/api/rest.py @@ -91,8 +91,8 @@ async def acquire(self, client: RESTClient) -> str: def invalidate(self, token: typing.Optional[str]) -> None: """Invalidate the cached token in this handler. - .. note:: - `token` may be provided in-order to avoid newly generated tokens + !!! note + [`token`][] may be provided in-order to avoid newly generated tokens from being invalidated due to multiple calls being made by separate subroutines which are handling the same token. @@ -125,7 +125,7 @@ def entity_factory(self) -> entity_factory_.EntityFactory: def token_type(self) -> typing.Union[str, applications.TokenType, None]: """Type of token this client is using for most requests. - If this is `None` then this client will likely only work + If this is [`None`][] then this client will likely only work for some endpoints such as public and webhook ones. """ @@ -149,23 +149,22 @@ async def fetch_channel( ------- hikari.channels.PartialChannel The channel. This will be a _derivative_ of - `hikari.channels.PartialChannel`, depending on the type of + [`hikari.channels.PartialChannel`][], depending on the type of channel you request for. This means that you may get one of - `hikari.channels.DMChannel`, - `hikari.channels.GroupDMChannel`, - `hikari.channels.GuildTextChannel`, - `hikari.channels.GuildVoiceChannel`, - `hikari.channels.GuildStoreChannel`, - `hikari.channels.GuildNewsChannel`. - - Likewise, the `hikari.channels.GuildChannel` can be used to + [`hikari.channels.DMChannel`][], + [`hikari.channels.GroupDMChannel`][], + [`hikari.channels.GuildTextChannel`][], + [`hikari.channels.GuildVoiceChannel`][], + [`hikari.channels.GuildNewsChannel`][]. + + Likewise, the [`hikari.channels.GuildChannel`][] can be used to determine if a channel is guild-bound, and - `hikari.channels.TextableChannel` can be used to determine + [`hikari.channels.TextableChannel`][] can be used to determine if the channel provides textual functionality to the application. - You can check for these using the `isinstance` + You can check for these using the [`isinstance`][] builtin function. Raises @@ -173,7 +172,7 @@ async def fetch_channel( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -236,8 +235,8 @@ async def edit_channel( If provided, the new name for the channel. flags : hikari.undefined.UndefinedOr[hikari.channels.ChannelFlag] If provided, the new channel flags to use for the channel. This can - only be used on a forum channel to apply `REQUIRE_TAG`, or - on a forum thread to apply `PINNED`. + only be used on a forum channel to apply [`hikari.channels.ChannelFlag.REQUIRE_TAG`][], or + on a forum thread to apply [`hikari.channels.ChannelFlag.PINNED`][]. position : hikari.undefined.UndefinedOr[int] If provided, the new position for the channel. topic : hikari.undefined.UndefinedOr[str] @@ -254,7 +253,7 @@ async def edit_channel( If provided, the new rate limit per user in the channel. region : hikari.undefined.UndefinedNoneOr[typing.Union[str, hikari.voices.VoiceRegion]] If provided, the voice region to set for this channel. Passing - `None` here will set it to "auto" mode where the used + [`None`][] here will set it to "auto" mode where the used region will be decided based on the first person who connects to it when it's empty. permission_overwrites : hikari.undefined.UndefinedOr[typing.Sequence[hikari.channels.PermissionOverwrite]] @@ -267,7 +266,7 @@ async def edit_channel( This should be either 60, 1440, 4320 or 10080 minutes and, as of writing, ignores the parent channel's set default_auto_archive_duration - when passed as `hikari.undefined.UNDEFINED`. + when passed as [`hikari.undefined.UNDEFINED`][]. default_thread_rate_limit_per_user : hikari.undefined.UndefinedOr[hikari.internal.time.Intervalish] If provided, the ratelimit that should be set in threads derived from this channel. @@ -292,7 +291,7 @@ async def edit_channel( If provided, the new locked state for the thread. This only applies to threads. - If it's locked then only people with `MANAGE_THREADS` can unarchive it. + If it's locked then only people with [`hikari.permissions.Permissions.MANAGE_THREADS`][] can unarchive it. invitable : undefined.UndefinedOr[bool] If provided, the new setting for whether non-moderators can invite new members to a private thread. This only applies to threads. @@ -360,8 +359,8 @@ async def follow_channel( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_WEBHOOKS` permission in the target - channel or are missing the `VIEW_CHANNEL` permission in the origin + If you are missing the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission in the target + channel or are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the origin channel. hikari.errors.NotFoundError If the origin or target channel is not found. @@ -378,7 +377,7 @@ async def delete_channel( ) -> channels_.PartialChannel: """Delete a channel in a guild, or close a DM. - .. note:: + !!! note For Public servers, the set 'Rules' or 'Guidelines' channels and the 'Public Server Updates' channel cannot be deleted. @@ -398,7 +397,7 @@ async def delete_channel( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -419,7 +418,7 @@ async def edit_my_voice_state( ) -> None: """Edit the current user's voice state in a stage channel. - .. note:: + !!! note The current user has to have already joined the target stage channel before any calls can be made to this endpoint. @@ -434,14 +433,14 @@ async def edit_my_voice_state( ---------------- suppress : hikari.undefined.UndefinedOr[bool] If specified, whether the user should be allowed to become a speaker - in the target stage channel with `builtin.True` suppressing them from + in the target stage channel with [`True`][] suppressing them from becoming one. request_to_speak : typing.Union[hikari.undefined.UndefinedType, bool, datetime.datetime] Whether to request to speak. This may be one of the following: - * `True` to indicate that the bot wants to speak. - * `False` to remove any previously set request to speak. - * `datetime.datetime` to specify when they want their request to + * [`True`][] to indicate that the bot wants to speak. + * [`False`][] to remove any previously set request to speak. + * [`datetime.datetime`][] to specify when they want their request to speak timestamp to be set to. If a datetime from the past is passed then Discord will use the current time instead. @@ -452,7 +451,7 @@ async def edit_my_voice_state( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MUTE_MEMBERS` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.MUTE_MEMBERS`][] permission in the channel. hikari.errors.NotFoundError If the channel, message or voice state is not found. hikari.errors.RateLimitTooLongError @@ -473,18 +472,18 @@ async def edit_voice_state( ) -> None: """Edit an existing voice state in a stage channel. - .. note:: + !!! note The target user must already be present in the stage channel before any calls are made to this endpoint. Parameters ---------- guild : hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild] - Object or Id of the guild to edit a voice state in. + Object or ID of the guild to edit a voice state in. channel : hikari.snowflakes.SnowflakeishOr[hikari.channels.GuildStageChannel] - Object or Id of the channel to edit a voice state in. + Object or ID of the channel to edit a voice state in. user : hikari.snowflakes.SnowflakeishOr[hikari.users.PartialUser] - Object or Id of the user to to edit the voice state of. + Object or ID of the user to edit the voice state of. Other Parameters ---------------- @@ -499,7 +498,7 @@ async def edit_voice_state( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MUTE_MEMBERS` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.MUTE_MEMBERS`][] permission in the channel. hikari.errors.NotFoundError If the channel, message or voice state is not found. hikari.errors.RateLimitTooLongError @@ -583,7 +582,8 @@ async def edit_permission_overwrite( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_PERMISSIONS` permission in the channel. + If you are missing the [`MANAGE_PERMISSIONS`][hikari.permissions.Permissions.MANAGE_ROLES] + permission in the channel. hikari.errors.NotFoundError If the channel is not found or the target is not found if it is a role. @@ -617,7 +617,8 @@ async def delete_permission_overwrite( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_PERMISSIONS` permission in the channel. + If you are missing the [`MANAGE_PERMISSIONS`][hikari.permissions.Permissions.MANAGE_ROLES] + permission in the channel. hikari.errors.NotFoundError If the channel is not found or the target is not found. hikari.errors.RateLimitTooLongError @@ -649,7 +650,7 @@ async def fetch_channel_invites( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found in any guilds you are a member of. hikari.errors.RateLimitTooLongError @@ -699,16 +700,16 @@ async def create_invite( If provided, the target user id for this invite. This may be the object or the ID of an existing user. - .. note:: - This is required if `target_type` is `STREAM` and the targeted + !!! note + This is required if `target_type` is [`hikari.invites.TargetType.STREAM`][] and the targeted user must be streaming into the channel. target_application : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialApplication]] If provided, the target application id for this invite. This may be the object or the ID of an existing application. - .. note:: - This is required if `target_type` is `EMBEDDED_APPLICATION` and - the targeted application must have the `EMBEDDED` flag. + !!! note + This is required if `target_type` is [`hikari.invites.TargetType.EMBEDDED_APPLICATION`][] and + the targeted application must have the [`hikari.applications.ApplicationFlags.EMBEDDED`][] flag. reason : hikari.undefined.UndefinedOr[str] If provided, the reason that will be recorded in the audit logs. Maximum of 512 characters. @@ -725,7 +726,7 @@ async def create_invite( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNELS` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission. hikari.errors.NotFoundError If the channel is not found, or if the target user does not exist, if provided. @@ -742,23 +743,23 @@ def trigger_typing( ) -> special_endpoints.TypingIndicator: """Trigger typing in a text channel. - .. note:: + !!! note The result of this call can be awaited to trigger typing once, or can be used as an async context manager to continually type until the context manager is left. Any errors documented below will happen then. Examples -------- - .. code-block:: python - + ```py # Trigger typing just once. await rest.trigger_typing(channel) # Trigger typing repeatedly for 1 minute. async with rest.trigger_typing(channel): await asyncio.sleep(60) + ``` - .. warning:: + !!! warning Sending a message to the channel will cause the typing indicator to disappear until it is re-triggered. @@ -778,7 +779,7 @@ def trigger_typing( 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. + If you are missing the [`hikari.permissions.Permissions.SEND_MESSAGES`][] in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -810,7 +811,7 @@ async def fetch_pins( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -842,7 +843,7 @@ async def pin_message( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_MESSAGES` in the channel. + If you are missing the [`hikari.permissions.Permissions.MANAGE_MESSAGES`][] in the channel. hikari.errors.NotFoundError If the channel is not found, or if the message does not exist in the given channel. @@ -875,7 +876,7 @@ async def unpin_message( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_MESSAGES` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_MESSAGES`][] permission. hikari.errors.NotFoundError If the channel is not found or the message is not a pinned message in the given channel. @@ -897,12 +898,12 @@ def fetch_messages( ) -> iterators.LazyIterator[messages_.Message]: """Browse the message history for a given text channel. - .. note:: + !!! note This call is not a coroutine function, it returns a special type of lazy iterator that will perform API calls as you iterate across it, thus any errors documented below will happen then. - See `hikari.iterators` for the full API for this iterator type. + See [`hikari.iterators`][] for the full API for this iterator type. Parameters ---------- @@ -940,7 +941,7 @@ def fetch_messages( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGE_HISTORY` in the channel. + If you are missing the [`hikari.permissions.Permissions.READ_MESSAGE_HISTORY`][] in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -977,7 +978,7 @@ async def fetch_message( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGE_HISTORY` in the channel. + If you are missing the [`hikari.permissions.Permissions.READ_MESSAGE_HISTORY`][] in the channel. hikari.errors.NotFoundError If the channel is not found or the message is not found in the given text channel. @@ -1025,15 +1026,15 @@ async def create_message( The channel to create the message in. content : hikari.undefined.UndefinedOr[typing.Any] If provided, the message contents. If - `hikari.undefined.UNDEFINED`, then nothing will be sent + [`hikari.undefined.UNDEFINED`][], then nothing will be sent in the content. Any other value here will be cast to a - `str`. + [`str`][]. - If this is a `hikari.embeds.Embed` and no `embed` nor `embeds` kwarg + 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 + 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. @@ -1046,26 +1047,26 @@ async def create_message( Attachments can be passed as many different things, to aid in convenience. - - If a `pathlib.PurePath` or `str` to a valid URL, the + - 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. + [`hikari.files.WebResource`][] such as + [`hikari.files.URL`][], + [`hikari.messages.Attachment`][], + [`hikari.emojis.Emoji`][], + [`hikari.embeds.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` + - 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 + - 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 + 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]] @@ -1097,7 +1098,6 @@ async def create_message( reply_must_exist : hikari.undefined.UndefinedOr[bool] If provided, whether to error if the message being replied to does not exist instead of sending as a normal (non-reply) message. - Defaults to `True`. This will not do anything if not being used with `reply`. mentions_everyone : hikari.undefined.UndefinedOr[bool] @@ -1109,28 +1109,28 @@ async def create_message( 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 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 + [`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 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 + [`hikari.snowflakes.Snowflake`][], or + [`hikari.guilds.PartialRole`][] derivatives to enforce mentioning specific roles. flags : hikari.undefined.UndefinedOr[hikari.messages.MessageFlag] If provided, optional flags to set on the message. If - `hikari.undefined.UNDEFINED`, then nothing is changed. + [`hikari.undefined.UNDEFINED`][], then nothing is changed. Note that some flags may not be able to be set. Currently the only - flags that can be set are `SUPPRESS_NOTIFICATIONS` and - `SUPPRESS_EMBEDS`. + flags that can be set are [hikari.messages.MessageFlag.SUPPRESS_NOTIFICATIONS] and + [hikari.messages.MessageFlag.SUPPRESS_EMBEDS]. Returns ------- @@ -1154,8 +1154,9 @@ async def create_message( 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. + If you are missing the [hikari.permissions.Permissions.SEND_MESSAGES] + in the channel or the person you are trying to message has the DM's + disabled. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -1193,9 +1194,11 @@ async def crosspost_message( If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError If you try to crosspost a message by the current user without the - `SEND_MESSAGES` permission for the target news channel or try to - crosspost a message by another user without both the `SEND_MESSAGES` - and `MANAGE_MESSAGES` permissions for the target channel. + [`hikari.permissions.Permissions.SEND_MESSAGES`][] permission for the + target news channel or try to crosspost a message by another user + without both the [`hikari.permissions.Permissions.SEND_MESSAGES`][] + and [`hikari.permissions.Permissions.MANAGE_MESSAGES`][] permissions + for the target channel. hikari.errors.NotFoundError If the channel or message is not found. hikari.errors.RateLimitTooLongError @@ -1236,12 +1239,12 @@ async def edit_message( ) -> messages_.Message: """Edit an existing message in a given channel. - .. warning:: + !!! warning If the message was not sent by your user, the only parameter you may provide to this call is the `flags` parameter. Anything - else will result in a `hikari.errors.ForbiddenError` being raised. + else will result in a [`hikari.errors.ForbiddenError`][] being raised. - .. note:: + !!! note Mentioning everyone, roles, or users in message edits currently will not send a push notification showing a new mention to people on Discord. It will still highlight in their chat as if they @@ -1249,7 +1252,7 @@ async def edit_message( Also important to note that if you specify a text `content`, `mentions_everyone`, `mentions_reply`, `user_mentions`, and `role_mentions` will default - to `False` as the message will be re-parsed for mentions. This will + to [`False`][] as the message will be re-parsed for mentions. This will also occur if only one of the four are specified This is a limitation of Discord's design. If in doubt, specify all @@ -1265,14 +1268,14 @@ async def edit_message( of an existing message. content : hikari.undefined.UndefinedOr[typing.Any] If provided, the message content to update with. If - `hikari.undefined.UNDEFINED`, then the content will not - be changed. If `None`, then the content will be removed. + [`hikari.undefined.UNDEFINED`][], then the content will not + be changed. If [`None`][], then the content will be removed. - Any other value will be cast to a `str` before sending. + Any other value will be cast to a [`str`][] before sending. - If this is a `hikari.embeds.Embed` and neither the `embed` or + If this is a [`hikari.embeds.Embed`][] and neither the `embed` or `embeds` kwargs are provided or if this is a - `hikari.files.Resourceish` and neither the + [`hikari.files.Resourceish`][] and neither the `attachment` or `attachments` kwargs are provided, the values will be overwritten. This allows for simpler syntax when sending an embed or an attachment alone. @@ -1281,41 +1284,41 @@ async def edit_message( ---------------- attachment : hikari.undefined.UndefinedNoneOr[typing.Union[hikari.files.Resourceish, hikari.messages.Attachment]] If provided, the attachment to set on the message. If - `hikari.undefined.UNDEFINED`, the previous attachment, if - present, is not changed. If this is `None`, then the + [`hikari.undefined.UNDEFINED`][], the previous attachment, if + present, is not changed. If this is [`None`][], then the attachment is removed, if present. Otherwise, the new attachment that was provided will be attached. attachments : hikari.undefined.UndefinedNoneOr[typing.Sequence[typing.Union[hikari.files.Resourceish, hikari.messages.Attachment]]] If provided, the attachments to set on the message. If - `hikari.undefined.UNDEFINED`, the previous attachments, if - present, are not changed. If this is `None`, then the + [`hikari.undefined.UNDEFINED`][], the previous attachments, if + present, are not changed. If this is [`None`][], then the attachments is removed, if present. Otherwise, the new attachments that were provided will be attached. component : hikari.undefined.UndefinedNoneOr[hikari.api.special_endpoints.ComponentBuilder] If provided, builder object of the component to set for this message. This component will replace any previously set components and passing - `None` will remove all components. + [`None`][] will remove all components. components : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.api.special_endpoints.ComponentBuilder]] If provided, a sequence of the component builder objects set for this message. These components will replace any previously set - components and passing `None` or an empty sequence will + components and passing [`None`][] or an empty sequence will remove all components. embed : hikari.undefined.UndefinedNoneOr[hikari.embeds.Embed] If provided, the embed to set on the message. If - `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed. - If this is `None` then any present embeds are removed. + [`hikari.undefined.UNDEFINED`][], the previous embed(s) are not changed. + If this is [`None`][] then any present embeds are removed. Otherwise, the new embed that was provided will be used as the replacement. embeds : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.embeds.Embed]] If provided, the embeds to set on the message. If - `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed. - If this is `None` then any present embeds are removed. + [`hikari.undefined.UNDEFINED`][], the previous embed(s) are not changed. + If this is [`None`][] then any present embeds are removed. Otherwise, the new embeds that were provided will be used as the replacement. mentions_everyone : hikari.undefined.UndefinedOr[bool] If provided, sanitation for `@everyone` mentions. If - `hikari.undefined.UNDEFINED`, then the previous setting is - not changed. If `True`, then `@everyone`/`@here` mentions + [`hikari.undefined.UNDEFINED`][], then the previous setting is + not changed. If [`True`][], then `@everyone`/`@here` mentions in the message content will show up as mentioning everyone that can view the chat. mentions_reply : hikari.undefined.UndefinedOr[bool] @@ -1325,32 +1328,33 @@ async def edit_message( This will not do anything if `message` is not a reply message. user_mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.users.PartialUser], bool]] If provided, sanitation for user mentions. If - `hikari.undefined.UNDEFINED`, then the previous setting is - not changed. If `True`, all valid user mentions will behave - as mentions. If `False`, all valid user mentions will not + [`hikari.undefined.UNDEFINED`][], then the previous setting is + not changed. If [`True`][], all valid user mentions will behave + as mentions. If [`False`][], all valid user mentions will not behave as mentions. You may alternatively pass a collection of - `hikari.snowflakes.Snowflake` user IDs, or - `hikari.users.PartialUser`-derived objects. + [`hikari.snowflakes.Snowflake`][] user IDs, or + [`hikari.users.PartialUser`][]-derived objects. role_mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.guilds.PartialRole], bool]] If provided, sanitation for role mentions. If - `hikari.undefined.UNDEFINED`, then the previous setting is - not changed. If `True`, all valid role mentions will behave - as mentions. If `False`, all valid role mentions will not + [`hikari.undefined.UNDEFINED`][], then the previous setting is + not changed. If [`True`][], all valid role mentions will behave + as mentions. If [`False`][], all valid role mentions will not behave as mentions. You may alternatively pass a collection of - `hikari.snowflakes.Snowflake` role IDs, or - `hikari.guilds.PartialRole`-derived objects. + [hikari.snowflakes.Snowflake] role IDs, or + [hikari.guilds.PartialRole]-derived objects. flags : hikari.undefined.UndefinedOr[hikari.messages.MessageFlag] If provided, optional flags to set on the message. If - `hikari.undefined.UNDEFINED`, then nothing is changed. + [`hikari.undefined.UNDEFINED`][], then nothing is changed. Note that some flags may not be able to be set. Currently the only - flags that can be set are `NONE` and `SUPPRESS_EMBEDS`. If you - have `MANAGE_MESSAGES` permissions, you can use this call to - suppress embeds on another user's message. + flags that can be set are [`hikari.messages.MessageFlag.NONE`][] and + [`hikari.messages.MessageFlag.SUPPRESS_EMBEDS`][]. If you + have [`hikari.permissions.Permissions.MANAGE_MESSAGES`][] permissions, you + can use this call to suppress embeds on another user's message. Returns ------- @@ -1370,9 +1374,9 @@ async def edit_message( 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; if you try to + If you are missing the [`hikari.permissions.Permissions.SEND_MESSAGES`][] in the channel; if you try to change the contents of another user's message; or if you try to edit - the flags on another user's message without the `MANAGE_MESSAGES` + the flags on another user's message without the [`hikari.permissions.Permissions.MANAGE_MESSAGES`][] permission. hikari.errors.NotFoundError If the channel or message is not found. @@ -1405,7 +1409,7 @@ async def delete_message( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_MESSAGES`, and the message is + If you are missing the [`hikari.permissions.Permissions.MANAGE_MESSAGES`][], and the message is not sent by you. hikari.errors.NotFoundError If the channel or message is not found. @@ -1430,7 +1434,7 @@ async def delete_messages( ) -> None: """Bulk-delete messages from the channel. - .. note:: + !!! note This API endpoint will only be able to delete 100 messages at a time. For anything more than this, multiple requests will be executed one-after-the-other, since the rate limits for this @@ -1442,12 +1446,12 @@ async def delete_messages( of this is that the `delete_message` endpoint is rate limited by a different bucket with different usage rates. - .. warning:: + !!! warning This endpoint is not atomic. If an error occurs midway through a bulk delete, you will **not** be able to revert any changes made up to this point. - .. warning:: + !!! warning Specifying any messages more than 14 days old will cause the call to fail, potentially with partial completion. @@ -1470,7 +1474,7 @@ async def delete_messages( hikari.errors.BulkDeleteError An error containing the messages successfully deleted, and the messages that were not removed. The - `BaseException.__cause__` of the exception will be the + [`BaseException.__cause__`][] of the exception will be the original error that terminated this process. """ @@ -1488,7 +1492,7 @@ async def add_reaction( ---------- channel : hikari.snowflakes.SnowflakeishOr[hikari.channels.TextableChannel] The channel where the message to add the reaction to is. This - may be a `hikari.channels.TextableChannel` or the ID of an existing + may be a [`hikari.channels.TextableChannel`][] or the ID of an existing channel. message : hikari.snowflakes.SnowflakeishOr[hikari.messages.PartialMessage] The message to add a reaction to. This may be the @@ -1511,7 +1515,7 @@ async def add_reaction( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `ADD_REACTIONS` (this is only necessary if you + If you are missing the [`hikari.permissions.Permissions.ADD_REACTIONS`][] (this is only necessary if you are the first person to add the reaction). hikari.errors.NotFoundError If the channel or message is not found. @@ -1600,7 +1604,7 @@ async def delete_all_reactions_for_emoji( If an invalid unicode emoji is given, or if the given custom emoji does not exist. hikari.errors.ForbiddenError - If you are missing the `MANAGE_MESSAGES` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_MESSAGES`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -1652,7 +1656,7 @@ async def delete_reaction( If an invalid unicode emoji is given, or if the given custom emoji does not exist. hikari.errors.ForbiddenError - If you are missing the `MANAGE_MESSAGES` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_MESSAGES`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -1687,7 +1691,7 @@ async def delete_all_reactions( If an invalid unicode emoji is given, or if the given custom emoji does not exist. hikari.errors.ForbiddenError - If you are missing the `MANAGE_MESSAGES` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_MESSAGES`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -1709,12 +1713,12 @@ def fetch_reactions_for_emoji( ) -> iterators.LazyIterator[users.User]: """Fetch reactions for an emoji from a message. - .. note:: + !!! note This call is not a coroutine function, it returns a special type of lazy iterator that will perform API calls as you iterate across it, thus any errors documented below will happen then. - See `hikari.iterators` for the full API for this iterator type. + See [`hikari.iterators`][] for the full API for this iterator type. Parameters ---------- @@ -1792,7 +1796,7 @@ async def create_webhook( hikari.errors.BadRequestError If `name` doesn't follow the restrictions enforced by discord. hikari.errors.ForbiddenError - If you are missing the `MANAGE_WEBHOOKS` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -1833,7 +1837,7 @@ async def fetch_webhook( Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_WEBHOOKS` permission when not + If you are missing the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission when not using a token. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). @@ -1856,7 +1860,7 @@ async def fetch_channel_webhooks( ---------- channel : hikari.snowflakes.SnowflakeishOr[hikari.channels.WebhookChannelT] The channel to fetch the webhooks for. This may be an instance of any - of the classes which are valid for `hikari.channels.WebhookChannelT` + of the classes which are valid for [`hikari.channels.WebhookChannelT`][] or the ID of an existing channel. Returns @@ -1869,7 +1873,7 @@ async def fetch_channel_webhooks( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_WEBHOOKS` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -1901,7 +1905,7 @@ async def fetch_guild_webhooks( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_WEBHOOKS` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission. hikari.errors.NotFoundError If the guild is not found. hikari.errors.RateLimitTooLongError @@ -1938,7 +1942,7 @@ async def edit_webhook( name : hikari.undefined.UndefinedOr[str] If provided, the new webhook name. avatar : hikari.undefined.UndefinedNoneOr[hikari.files.Resourceish] - If provided, the new webhook avatar. If `None`, will + If provided, the new webhook avatar. If [`None`][], will remove the webhook avatar. channel : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.channels.WebhookChannelT]] If provided, the text channel to move the webhook to. @@ -1954,7 +1958,7 @@ async def edit_webhook( Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_WEBHOOKS` permission when not + If you are missing the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission when not using a token. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). @@ -1991,7 +1995,7 @@ async def delete_webhook( Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_WEBHOOKS` permission when not + If you are missing the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission when not using a token. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). @@ -2035,12 +2039,12 @@ async def execute_webhook( ) -> messages_.Message: """Execute a webhook. - .. warning:: + !!! warning At the time of writing, `username` and `avatar_url` are ignored for interaction webhooks. - Additionally, `SUPPRESS_EMBEDS`, `SUPPRESS_NOTIFICATIONS` and `EPHEMERAL` - are the only flags that can be set, with `EPHEMERAL` limited to + Additionally, [`hikari.messages.MessageFlag.SUPPRESS_EMBEDS`][], [`hikari.messages.MessageFlag.SUPPRESS_NOTIFICATIONS`][] and [`hikari.messages.MessageFlag.EPHEMERAL`][] + are the only flags that can be set, with [`hikari.messages.MessageFlag.EPHEMERAL`][] limited to interaction webhooks. Parameters @@ -2052,16 +2056,16 @@ async def execute_webhook( The webhook token. content : hikari.undefined.UndefinedOr[typing.Any] If provided, the message contents. If - `hikari.undefined.UNDEFINED`, then nothing will be sent + [`hikari.undefined.UNDEFINED`][], then nothing will be sent in the content. Any other value here will be cast to a - `str`. + [`str`][]. - If this is a `hikari.embeds.Embed` and no `embed` nor + If this is a [`hikari.embeds.Embed`][] and no `embed` nor no `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 + 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. @@ -2086,26 +2090,26 @@ async def execute_webhook( Attachments can be passed as many different things, to aid in convenience. - - If a `pathlib.PurePath` or `str` to a valid URL, the + - 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. + [`hikari.files.WebResource`][] such as + [`hikari.files.URL`][], + [`hikari.messages.Attachment`][], + [`hikari.emojis.Emoji`][], + [`hikari.embeds.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` + - 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 + - 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 + 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]] @@ -2127,20 +2131,20 @@ async def execute_webhook( If provided, whether the message should parse @everyone/@here mentions. 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 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 + [`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 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 + [`hikari.snowflakes.Snowflake`][], or + [`hikari.guilds.PartialRole`][] derivatives to enforce mentioning specific roles. flags : typing.Union[hikari.undefined.UndefinedType, int, hikari.messages.MessageFlag] The flags to set for this webhook message. @@ -2259,7 +2263,7 @@ async def edit_webhook_message( ) -> messages_.Message: """Edit a message sent by a webhook. - .. note:: + !!! note Mentioning everyone, roles, or users in message edits currently will not send a push notification showing a new mention to people on Discord. It will still highlight in their chat as if they @@ -2267,7 +2271,7 @@ async def edit_webhook_message( Also important to note that if you specify a text `content`, `mentions_everyone`, `mentions_reply`, `user_mentions`, and `role_mentions` will default - to `False` as the message will be re-parsed for mentions. This will + to [`False`][] as the message will be re-parsed for mentions. This will also occur if only one of the four are specified This is a limitation of Discord's design. If in doubt, specify all @@ -2285,14 +2289,14 @@ async def edit_webhook_message( an existing message. content : hikari.undefined.UndefinedOr[typing.Any] If provided, the message content to update with. If - `hikari.undefined.UNDEFINED`, then the content will not - be changed. If `None`, then the content will be removed. + [`hikari.undefined.UNDEFINED`][], then the content will not + be changed. If [`None`][], then the content will be removed. - Any other value will be cast to a `str` before sending. + Any other value will be cast to a [`str`][] before sending. - If this is a `hikari.embeds.Embed` and neither the + If this is a [`hikari.embeds.Embed`][] and neither the `embed` or `embeds` kwargs are provided or if this is a - `hikari.files.Resourceish` and neither the `attachment` or + [`hikari.files.Resourceish`][] and neither the `attachment` or `attachments` kwargs are provided, the values will be overwritten. This allows for simpler syntax when sending an embed or an attachment alone. @@ -2307,58 +2311,58 @@ async def edit_webhook_message( This is required when trying to edit a thread message. attachment : hikari.undefined.UndefinedNoneOr[typing.Union[hikari.files.Resourceish, hikari.messages.Attachment]] If provided, the attachment to set on the message. If - `hikari.undefined.UNDEFINED`, the previous attachment, if - present, is not changed. If this is `None`, then the + [`hikari.undefined.UNDEFINED`][], the previous attachment, if + present, is not changed. If this is [`None`][], then the attachment is removed, if present. Otherwise, the new attachment that was provided will be attached. attachments : hikari.undefined.UndefinedNoneOr[typing.Sequence[typing.Union[hikari.files.Resourceish, hikari.messages.Attachment]]] If provided, the attachments to set on the message. If - `hikari.undefined.UNDEFINED`, the previous attachments, if - present, are not changed. If this is `None`, then the + [`hikari.undefined.UNDEFINED`][], the previous attachments, if + present, are not changed. If this is [`None`][], then the attachments is removed, if present. Otherwise, the new attachments that were provided will be attached. component : hikari.undefined.UndefinedNoneOr[hikari.api.special_endpoints.ComponentBuilder] If provided, builder object of the component to set for this message. This component will replace any previously set components and passing - `None` will remove all components. + [`None`][] will remove all components. components : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.api.special_endpoints.ComponentBuilder]] If provided, a sequence of the component builder objects set for this message. These components will replace any previously set - components and passing `None` or an empty sequence will + components and passing [`None`][] or an empty sequence will remove all components. embed : hikari.undefined.UndefinedNoneOr[hikari.embeds.Embed] If provided, the embed to set on the message. If - `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed. - If this is `None` then any present embeds are removed. + [`hikari.undefined.UNDEFINED`][], the previous embed(s) are not changed. + If this is [`None`][] then any present embeds are removed. Otherwise, the new embed that was provided will be used as the replacement. embeds : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.embeds.Embed]] If provided, the embeds to set on the message. If - `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed. - If this is `None` then any present embeds are removed. + [`hikari.undefined.UNDEFINED`][], the previous embed(s) are not changed. + If this is [`None`][] then any present embeds are removed. Otherwise, the new embeds that were provided will be used as the replacement. mentions_everyone : hikari.undefined.UndefinedOr[bool] If provided, sanitation for `@everyone` mentions. If - `hikari.undefined.UNDEFINED`, then the previous setting is - not changed. If `True`, then `@everyone`/`@here` mentions + [`hikari.undefined.UNDEFINED`][], then the previous setting is + not changed. If [`True`][], then `@everyone`/`@here` mentions in the message content will show up as mentioning everyone that can view the chat. 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 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 + [`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 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 + [`hikari.snowflakes.Snowflake`][], or + [`hikari.guilds.PartialRole`][] derivatives to enforce mentioning specific roles. Returns @@ -2439,7 +2443,7 @@ async def delete_webhook_message( async def fetch_gateway_url(self) -> str: """Fetch the gateway url. - .. note:: + !!! note This endpoint does not require any valid authorization. Raises @@ -2484,13 +2488,9 @@ async def fetch_invite( the code of an existing invite. with_counts : bool Whether the invite should contain the approximate member counts. - - Defaults to `True`. with_expiration: bool Whether the invite should contain the expiration date. - Defaults to `True`. - Returns ------- hikari.invites.Invite @@ -2527,8 +2527,8 @@ async def delete_invite(self, invite: typing.Union[invites.InviteCode, str]) -> Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_GUILD` permission in the guild - the invite is from or if you are missing the `MANAGE_CHANNELS` + If you are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission in the guild + the invite is from or if you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission in the channel the invite is from. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). @@ -2575,7 +2575,7 @@ async def edit_my_user( username : undefined.UndefinedOr[str] If provided, the new username. avatar : undefined.UndefinedNoneOr[hikari.files.Resourceish] - If provided, the new avatar. If `None`, + If provided, the new avatar. If [`None`][], the avatar will be removed. Returns @@ -2625,18 +2625,17 @@ def fetch_my_guilds( ) -> iterators.LazyIterator[applications.OwnGuild]: """Fetch the token's associated guilds. - .. note:: + !!! note This call is not a coroutine function, it returns a special type of lazy iterator that will perform API calls as you iterate across it, thus any errors documented below will happen then. - See `hikari.iterators` for the full API for this iterator type. + See [`hikari.iterators`][] for the full API for this iterator type. Other Parameters ---------------- newest_first : bool Whether to fetch the newest first or the oldest first. - Defaults to `False`. start_at : hikari.undefined.UndefinedOr[hikari.snowflakes.SearchableSnowflakeishOr[hikari.guilds.PartialGuild]] If provided, will start at this snowflake. If you provide a datetime object, it will be transformed into a snowflake. This @@ -2690,9 +2689,9 @@ async def fetch_my_user_application_role_connection( ) -> applications.OwnApplicationRoleConnection: """Fetch the token's associated role connections. - .. note:: + !!! note This requires the token to have the - `hikari.applications.OAuth2Scope.ROLE_CONNECTIONS_WRITE` scope enabled. + [`hikari.applications.OAuth2Scope.ROLE_CONNECTIONS_WRITE`][] scope enabled. Parameters ---------- @@ -2729,9 +2728,9 @@ async def set_my_user_application_role_connection( ) -> applications.OwnApplicationRoleConnection: """Set the token's associated role connections. - .. note:: + !!! note This requires the token to have the - `hikari.applications.OAuth2Scope.ROLE_CONNECTIONS_WRITE` scope enabled. + [`hikari.applications.OAuth2Scope.ROLE_CONNECTIONS_WRITE`][] scope enabled. Parameters ---------- @@ -2751,9 +2750,9 @@ async def set_my_user_application_role_connection( records through `set_application_role_connection_metadata_records`, this mapping should contain those keys to the valid type of the record: - - `INTEGER_X`: An `int`. - - `DATETIME_X`: A `datetime.datetime` object. - - `BOOLEAN_X`: A `bool`. + - `INTEGER_X`: An [`int`][]. + - `DATETIME_X`: A [`datetime.datetime`][] object. + - `BOOLEAN_X`: A [`bool`][]. Returns ------- @@ -2808,9 +2807,9 @@ async def create_dm_channel(self, user: snowflakes.SnowflakeishOr[users.PartialU async def fetch_application(self) -> applications.Application: """Fetch the token's associated application. - .. warning:: + !!! warning This endpoint can only be used with a Bot token. Using this with a - Bearer token will result in a `hikari.errors.UnauthorizedError`. + Bearer token will result in a [`hikari.errors.UnauthorizedError`][]. Returns ------- @@ -2833,9 +2832,9 @@ async def fetch_application(self) -> applications.Application: async def fetch_authorization(self) -> applications.AuthorizationInformation: """Fetch the token's authorization information. - .. warning:: + !!! warning This endpoint can only be used with a Bearer token. Using this - with a Bot token will result in a `hikari.errors.UnauthorizedError`. + with a Bot token will result in a [`hikari.errors.UnauthorizedError`][]. Returns ------- @@ -2859,9 +2858,9 @@ async def fetch_application_role_connection_metadata_records( ) -> typing.Sequence[applications.ApplicationRoleConnectionMetadataRecord]: """Fetch the application role connection metadata records. - .. note:: + !!! note This requires the token to have the - `hikari.applications.OAuth2Scope.ROLE_CONNECTIONS_WRITE` scope enabled. + [`hikari.applications.OAuth2Scope.ROLE_CONNECTIONS_WRITE`][] scope enabled. Parameters ---------- @@ -2894,9 +2893,9 @@ async def set_application_role_connection_metadata_records( ) -> typing.Sequence[applications.ApplicationRoleConnectionMetadataRecord]: """Set the application role connection metadata records. - .. note:: + !!! note This requires the token to have the - `hikari.applications.OAuth2Scope.ROLE_CONNECTIONS_WRITE` scope enabled. + [`hikari.applications.OAuth2Scope.ROLE_CONNECTIONS_WRITE`][] scope enabled. Parameters ---------- @@ -3014,10 +3013,10 @@ async def refresh_access_token( ) -> applications.OAuth2AuthorizationToken: """Refresh an access token. - .. warning:: + !!! warning As of writing this Discord currently ignores any passed scopes, therefore you should use - `hikari.applications.OAuth2AuthorizationToken.scopes` to validate + [`hikari.applications.OAuth2AuthorizationToken.scopes`][] to validate that the expected scopes were actually authorized here. Parameters @@ -3096,10 +3095,10 @@ async def add_user_to_guild( ) -> typing.Optional[guilds.Member]: """Add a user to a guild. - .. note:: + !!! note This requires the `access_token` to have the - `hikari.applications.OAuth2Scope.GUILDS_JOIN` scope enabled along - with the authorization of a Bot which has `MANAGE_INVITES` + [`hikari.applications.OAuth2Scope.GUILDS_JOIN`][] scope enabled along + with the authorization of a Bot which has [`hikari.permissions.Permissions.CREATE_INSTANT_INVITE`][] permission within the target guild. Parameters @@ -3118,26 +3117,26 @@ async def add_user_to_guild( nickname : hikari.undefined.UndefinedOr[str] If provided, the nick to add to the user when he joins the guild. - Requires the `MANAGE_NICKNAMES` permission on the guild. + Requires the [`hikari.permissions.Permissions.MANAGE_NICKNAMES`][] permission on the guild. roles : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishSequence[hikari.guilds.PartialRole]] If provided, the roles to add to the user when he joins the guild. This may be a collection objects or IDs of existing roles. - Requires the `MANAGE_ROLES` permission on the guild. + Requires the [`hikari.permissions.Permissions.MANAGE_ROLES`][] permission on the guild. mute : hikari.undefined.UndefinedOr[bool] If provided, the mute state to add the user when he joins the guild. - Requires the `MUTE_MEMBERS` permission on the guild. + Requires the [`hikari.permissions.Permissions.MUTE_MEMBERS`][] permission on the guild. deaf : hikari.undefined.UndefinedOr[bool] If provided, the deaf state to add the user when he joins the guild. - Requires the `DEAFEN_MEMBERS` permission on the guild. + Requires the [`hikari.permissions.Permissions.DEAFEN_MEMBERS`][] permission on the guild. Returns ------- typing.Optional[hikari.guilds.Member] - `None` if the user was already part of the guild, else - `hikari.guilds.Member`. + [`None`][] if the user was already part of the guild, else + [`hikari.guilds.Member`][]. Raises ------ @@ -3148,7 +3147,7 @@ async def add_user_to_guild( if you are missing permissions to do one of the things you specified, if you are using an access token for another user, if the token is bound to another bot or if the access token doesn't have the - `hikari.applications.OAuth2Scope.GUILDS_JOIN` scope enabled. + [`hikari.applications.OAuth2Scope.GUILDS_JOIN`][] scope enabled. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -3219,12 +3218,12 @@ def fetch_audit_log( ) -> iterators.LazyIterator[audit_logs.AuditLog]: """Fetch pages of the guild's audit log. - .. note:: + !!! note This call is not a coroutine function, it returns a special type of lazy iterator that will perform API calls as you iterate across it, thus any errors documented below will happen then. - See `hikari.iterators` for the full API for this iterator type. + See [`hikari.iterators`][] for the full API for this iterator type. Parameters ---------- @@ -3254,7 +3253,7 @@ def fetch_audit_log( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `VIEW_AUDIT_LOG` permission. + If you are missing the [`hikari.permissions.Permissions.VIEW_AUDIT_LOG`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.RateLimitTooLongError @@ -3278,7 +3277,7 @@ async def fetch_emoji( The guild to fetch the emoji from. This can be a guild object or the ID of an existing guild. emoji : hikari.snowflakes.SnowflakeishOr[hikari.emojis.CustomEmoji] - The emoji to fetch. This can be a `hikari.emojis.CustomEmoji` + The emoji to fetch. This can be a [`hikari.emojis.CustomEmoji`][] or the ID of an existing emoji. Returns @@ -3356,7 +3355,7 @@ async def create_emoji( ---------------- roles : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishSequence[hikari.guilds.PartialRole]] If provided, a collection of the roles that will be able to - use this emoji. This can be a `hikari.guilds.PartialRole` or + use this emoji. This can be a [`hikari.guilds.PartialRole`][] or the ID of an existing role. reason : hikari.undefined.UndefinedOr[str] If provided, the reason that will be recorded in the audit logs. @@ -3373,7 +3372,8 @@ async def create_emoji( If any of the fields that are passed have an invalid value or if there are no more spaces for the type of emoji in the guild. hikari.errors.ForbiddenError - If you are missing `MANAGE_EMOJIS_AND_STICKERS` in the server. + If you are missing [`hikari.permissions.Permissions.MANAGE_GUILD_EXPRESSIONS`][] + in the server. hikari.errors.NotFoundError If the guild is not found. hikari.errors.UnauthorizedError @@ -3403,7 +3403,7 @@ async def edit_emoji( The guild to edit the emoji on. This can be a guild object or the ID of an existing guild. emoji : hikari.snowflakes.SnowflakeishOr[hikari.emojis.CustomEmoji] - The emoji to edit. This can be a `hikari.emojis.CustomEmoji` + The emoji to edit. This can be a [`hikari.emojis.CustomEmoji`][] or the ID of an existing emoji. Other Parameters @@ -3412,7 +3412,7 @@ async def edit_emoji( If provided, the new name for the emoji. roles : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishSequence[hikari.guilds.PartialRole]] If provided, the new collection of roles that will be able to - use this emoji. This can be a `hikari.guilds.PartialRole` or + use this emoji. This can be a [`hikari.guilds.PartialRole`][] or the ID of an existing role. reason : hikari.undefined.UndefinedOr[str] If provided, the reason that will be recorded in the audit logs. @@ -3428,7 +3428,8 @@ async def edit_emoji( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing `MANAGE_EMOJIS_AND_STICKERS` in the server. + If you are missing [`hikari.permissions.Permissions.MANAGE_GUILD_EXPRESSIONS`][] + in the server. hikari.errors.NotFoundError If the guild or the emoji are not found. hikari.errors.UnauthorizedError @@ -3456,7 +3457,7 @@ async def delete_emoji( The guild to delete the emoji on. This can be a guild object or the ID of an existing guild. emoji : hikari.snowflakes.SnowflakeishOr[hikari.emojis.CustomEmoji] - The emoji to delete. This can be a `hikari.emojis.CustomEmoji` + The emoji to delete. This can be a [`hikari.emojis.CustomEmoji`][] or the ID of an existing emoji. Other Parameters @@ -3468,7 +3469,8 @@ async def delete_emoji( Raises ------ hikari.errors.ForbiddenError - If you are missing `MANAGE_EMOJIS_AND_STICKERS` in the server. + If you are missing [`hikari.permissions.Permissions.MANAGE_GUILD_EXPRESSIONS`][] + in the server. hikari.errors.NotFoundError If the guild or the emoji are not found. hikari.errors.UnauthorizedError @@ -3623,7 +3625,7 @@ async def create_sticker( The 320x320 image for the sticker. Maximum upload size is 500kb. This can be a still PNG, an animated PNG, a Lottie, or a GIF. - .. note:: + !!! note Lottie support is only available for verified and partnered servers. @@ -3646,7 +3648,8 @@ async def create_sticker( If any of the fields that are passed have an invalid value or if there are no more spaces for the sticker in the guild. hikari.errors.ForbiddenError - If you are missing `MANAGE_EMOJIS_AND_STICKERS` in the server. + If you are missing [`hikari.permissions.Permissions.MANAGE_GUILD_EXPRESSIONS`][] + in the server. hikari.errors.NotFoundError If the guild is not found. hikari.errors.UnauthorizedError @@ -3702,7 +3705,8 @@ async def edit_sticker( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing `MANAGE_EMOJIS_AND_STICKERS` in the server. + If you are missing [`hikari.permissions.Permissions.MANAGE_GUILD_EXPRESSIONS`][] + in the server. hikari.errors.NotFoundError If the guild or the sticker are not found. hikari.errors.UnauthorizedError @@ -3742,7 +3746,8 @@ async def delete_sticker( Raises ------ hikari.errors.ForbiddenError - If you are missing `MANAGE_EMOJIS_AND_STICKERS` in the server. + If you are missing [`hikari.permissions.Permissions.MANAGE_GUILD_EXPRESSIONS`][] + in the server. hikari.errors.NotFoundError If the guild or the sticker are not found. hikari.errors.UnauthorizedError @@ -3758,15 +3763,15 @@ async def delete_sticker( def guild_builder(self, name: str, /) -> special_endpoints.GuildBuilder: """Make a guild builder to create a guild with. - .. note:: + !!! note This endpoint can only be used by bots in less than 10 guilds. - .. note:: + !!! note This call is not a coroutine function, it returns a special type of lazy iterator that will perform API calls as you iterate across it, thus any errors documented below will happen then. - See `hikari.iterators` for the full API for this iterator type. + See [`hikari.iterators`][] for the full API for this iterator type. Parameters ---------- @@ -3777,7 +3782,7 @@ def guild_builder(self, name: str, /) -> special_endpoints.GuildBuilder: ------- hikari.api.special_endpoints.GuildBuilder The guild builder to use. This will allow to create a guild - later with `hikari.api.special_endpoints.GuildBuilder.create`. + later with [`hikari.api.special_endpoints.GuildBuilder.create`][]. Raises ------ @@ -3794,7 +3799,7 @@ def guild_builder(self, name: str, /) -> special_endpoints.GuildBuilder: See Also -------- - GuildBuilder : `hikari.api.special_endpoints.GuildBuilder`. + GuildBuilder : [`hikari.api.special_endpoints.GuildBuilder`][]. """ @abc.abstractmethod @@ -3831,7 +3836,7 @@ async def fetch_guild(self, guild: snowflakes.SnowflakeishOr[guilds.PartialGuild async def fetch_guild_preview(self, guild: snowflakes.SnowflakeishOr[guilds.PartialGuild]) -> guilds.GuildPreview: """Fetch a guild preview. - .. note:: + !!! note This will only work for guilds you are a part of or are public. Parameters @@ -3917,18 +3922,18 @@ async def edit_guild( If provided, the new afk timeout. icon : hikari.undefined.UndefinedOr[hikari.files.Resourceish] If provided, the new guild icon. Must be a 1024x1024 image or can be - an animated gif when the guild has the `ANIMATED_ICON` feature. + an animated gif when the guild has the [`hikari.guilds.GuildFeature.ANIMATED_ICON`][] feature. owner : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.users.PartialUser]]] If provided, the new guild owner. - .. warning:: + !!! warning You need to be the owner of the server to use this. splash : hikari.undefined.UndefinedNoneOr[hikari.files.Resourceish] If provided, the new guild splash. Must be a 16:9 image and the - guild must have the `INVITE_SPLASH` feature. + guild must have the [`hikari.guilds.GuildFeature.INVITE_SPLASH`][] feature. banner : hikari.undefined.UndefinedNoneOr[hikari.files.Resourceish] If provided, the new guild banner. Must be a 16:9 image and the - guild must have the `BANNER` feature. + guild must have the [`hikari.guilds.GuildFeature.BANNER`][] feature. system_channel : hikari.undefined.UndefinedNoneOr[hikari.snowflakes.SnowflakeishOr[hikari.channels.GuildTextChannel]] If provided, the new system channel. rules_channel : hikari.undefined.UndefinedNoneOr[hikari.snowflakes.SnowflakeishOr[hikari.channels.GuildTextChannel]] @@ -3961,7 +3966,7 @@ async def edit_guild( If any of the fields that are passed have an invalid value. Or you are missing the hikari.errors.ForbiddenError - If you are missing the `MANAGE_GUILD` permission or if you tried to + If you are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission or if you tried to pass ownership without being the server owner. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). @@ -4080,7 +4085,7 @@ async def create_guild_text_channel( This should be either 60, 1440, 4320 or 10080 minutes and, as of writing, ignores the parent channel's set default_auto_archive_duration - when passed as `hikari.undefined.UNDEFINED`. + when passed as [`hikari.undefined.UNDEFINED`][]. reason : hikari.undefined.UndefinedOr[str] If provided, the reason that will be recorded in the audit logs. Maximum of 512 characters. @@ -4095,7 +4100,7 @@ async def create_guild_text_channel( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -4158,7 +4163,7 @@ async def create_guild_news_channel( This should be either 60, 1440, 4320 or 10080 minutes and, as of writing, ignores the parent channel's set default_auto_archive_duration - when passed as `hikari.undefined.UNDEFINED`. + when passed as [`hikari.undefined.UNDEFINED`][]. reason : hikari.undefined.UndefinedOr[str] If provided, the reason that will be recorded in the audit logs. Maximum of 512 characters. @@ -4173,7 +4178,7 @@ async def create_guild_news_channel( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -4244,7 +4249,7 @@ async def create_guild_forum_channel( This should be either 60, 1440, 4320 or 10080 minutes and, as of writing, ignores the parent channel's set default_auto_archive_duration - when passed as `hikari.undefined.UNDEFINED`. + when passed as [`hikari.undefined.UNDEFINED`][]. default_thread_rate_limit_per_user : hikari.undefined.UndefinedOr[hikari.internal.time.Intervalish] If provided, the ratelimit that should be set in threads created from the forum. @@ -4270,7 +4275,7 @@ async def create_guild_forum_channel( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -4327,7 +4332,7 @@ async def create_guild_voice_channel( If provided, the permission overwrites for the channel. region : hikari.undefined.UndefinedOr[typing.Union[hikari.voices.VoiceRegion, str]] If provided, the voice region to for this channel. Passing - `None` here will set it to "auto" mode where the used + [`None`][] here will set it to "auto" mode where the used region will be decided based on the first person who connects to it when it's empty. category : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.channels.GuildCategory]] @@ -4347,7 +4352,7 @@ async def create_guild_voice_channel( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -4401,7 +4406,7 @@ async def create_guild_stage_channel( If provided, the permission overwrites for the channel. region : hikari.undefined.UndefinedOr[typing.Union[hikari.voices.VoiceRegion, str]] If provided, the voice region to for this channel. Passing - `None` here will set it to "auto" mode where the used + [`None`][] here will set it to "auto" mode where the used region will be decided based on the first person who connects to it when it's empty. category : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.channels.GuildCategory]] @@ -4421,7 +4426,7 @@ async def create_guild_stage_channel( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -4475,7 +4480,7 @@ async def create_guild_category( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -4503,7 +4508,7 @@ async def create_message_thread( ) -> typing.Union[channels_.GuildPublicThread, channels_.GuildNewsThread]: """Create a public or news thread on a message in a guild channel. - .. note:: + !!! note This call may create a public or news thread dependent on the target channel's type and cannot create private threads. @@ -4523,7 +4528,7 @@ async def create_message_thread( This should be either 60, 1440, 4320 or 10080 minutes and, as of writing, ignores the parent channel's set default_auto_archive_duration - when passed as `hikari.undefined.UNDEFINED`. + when passed as [`hikari.undefined.UNDEFINED`][]. rate_limit_per_user : hikari.undefined.UndefinedOr[hikari.internal.time.Intervalish] If provided, the amount of seconds a user has to wait before being able to send another message in the channel. @@ -4542,7 +4547,7 @@ async def create_message_thread( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `CREATE_PUBLIC_THREADS` permission or if you + If you are missing the [`hikari.permissions.Permissions.CREATE_PUBLIC_THREADS`][] permission or if you can't send messages in the target channel. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). @@ -4570,7 +4575,7 @@ async def create_thread( ) -> channels_.GuildThreadChannel: """Create a thread in a guild channel. - .. warning:: + !!! warning Private and public threads can only be made in guild text channels, and news threads can only be made in guild news channels. @@ -4590,7 +4595,7 @@ async def create_thread( This should be either 60, 1440, 4320 or 10080 minutes and, as of writing, ignores the parent channel's set default_auto_archive_duration - when passed as `hikari.undefined.UNDEFINED`. + when passed as [`hikari.undefined.UNDEFINED`][]. invitable : undefined.UndefinedOr[bool] If provided, whether non-moderators should be able to add other non-moderators to the thread. @@ -4613,7 +4618,7 @@ async def create_thread( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `CREATE_PUBLIC_THREADS` permission or if you + If you are missing the [`hikari.permissions.Permissions.CREATE_PUBLIC_THREADS`][] permission or if you can't send messages in the target channel. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). @@ -4669,15 +4674,15 @@ async def create_forum_post( Name of the post. content : hikari.undefined.UndefinedOr[typing.Any] If provided, the message contents. If - `hikari.undefined.UNDEFINED`, then nothing will be sent + [`hikari.undefined.UNDEFINED`][], then nothing will be sent in the content. Any other value here will be cast to a - `str`. + [`str`][]. - If this is a `hikari.embeds.Embed` and no `embed` nor `embeds` kwarg + 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 + 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. @@ -4690,26 +4695,26 @@ async def create_forum_post( Attachments can be passed as many different things, to aid in convenience. - - If a `pathlib.PurePath` or `str` to a valid URL, the + - 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. + [`hikari.files.WebResource`][] such as + [`hikari.files.URL`][], + [`hikari.messages.Attachment`][], + [`hikari.emojis.Emoji`][], + [`hikari.embeds.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` + - 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 + - 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 + 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]] @@ -4745,33 +4750,33 @@ async def create_forum_post( 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 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 + [`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 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 + [`hikari.snowflakes.Snowflake`][], or + [`hikari.guilds.PartialRole`][] derivatives to enforce mentioning specific roles. flags : hikari.undefined.UndefinedOr[hikari.messages.MessageFlag] If provided, optional flags to set on the message. If - `hikari.undefined.UNDEFINED`, then nothing is changed. + [`hikari.undefined.UNDEFINED`][], then nothing is changed. Note that some flags may not be able to be set. Currently the only - flags that can be set are `NONE` and `SUPPRESS_EMBEDS`. + flags that can be set are [`hikari.messages.MessageFlag.NONE`][] and [`hikari.messages.MessageFlag.SUPPRESS_EMBEDS`][]. auto_archive_duration : hikari.undefined.UndefinedOr[hikari.internal.time.Intervalish] If provided, how long the post should remain inactive until it's archived. This should be either 60, 1440, 4320 or 10080 minutes and, as of writing, ignores the parent channel's set default_auto_archive_duration - when passed as `hikari.undefined.UNDEFINED`. + when passed as [`hikari.undefined.UNDEFINED`][]. rate_limit_per_user : hikari.undefined.UndefinedOr[hikari.internal.time.Intervalish] If provided, the amount of seconds a user has to wait before being able to send another message in the channel. @@ -4792,7 +4797,7 @@ async def create_forum_post( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `SEND_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.SEND_MESSAGES`][] permission in the channel. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.RateLimitTooLongError @@ -5032,7 +5037,7 @@ def fetch_public_archived_threads( ) -> iterators.LazyIterator[typing.Union[channels_.GuildNewsThread, channels_.GuildPublicThread]]: """Fetch a channel's public archived threads. - .. note:: + !!! note The exceptions on this endpoint will only be raised once the result is awaited or iterated over. Invoking this function itself will not raise anything. @@ -5054,10 +5059,10 @@ def fetch_public_archived_threads( hikari.iterators.LazyIterator[typing.Union[hikari.channels.GuildNewsChannel, hikari.channels.GuildPublicThread]] An iterator to fetch the threads. - .. note:: + !!! note This call is not a coroutine function, it returns a special type of lazy iterator that will perform API calls as you iterate across it. - See `hikari.iterators` for the full API for this iterator type. + See [`hikari.iterators`][] for the full API for this iterator type. Raises ------ @@ -5084,7 +5089,7 @@ def fetch_private_archived_threads( ) -> iterators.LazyIterator[channels_.GuildPrivateThread]: """Fetch a channel's private archived threads. - .. note:: + !!! note The exceptions on this endpoint will only be raised once the result is awaited or iterated over. Invoking this function itself will not raise anything. @@ -5106,17 +5111,17 @@ def fetch_private_archived_threads( hikari.iterators.LazyIterator[hikari.channels.GuildPrivateThread] An iterator to fetch the threads. - .. note:: + !!! note This call is not a coroutine function, it returns a special type of lazy iterator that will perform API calls as you iterate across it. - See `hikari.iterators` for the full API for this iterator type. + See [`hikari.iterators`][] for the full API for this iterator type. Raises ------ hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you do not have `MANAGE_THREADS` in the target channel. + If you do not have [`hikari.permissions.Permissions.MANAGE_THREADS`][] in the target channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -5138,7 +5143,7 @@ def fetch_joined_private_archived_threads( ) -> iterators.LazyIterator[channels_.GuildPrivateThread]: """Fetch the private archived threads you have joined in a channel. - .. note:: + !!! note The exceptions on this endpoint will only be raised once the result is awaited or iterated over. Invoking this function itself will not raise anything. @@ -5159,10 +5164,10 @@ def fetch_joined_private_archived_threads( hikari.iterators.LazyIterator[hikari.channels.GuildPrivateThread] An iterator to fetch the threads. - .. note:: + !!! note This call is not a coroutine function, it returns a special type of lazy iterator that will perform API calls as you iterate across it. - See `hikari.iterators` for the full API for this iterator type. + See [`hikari.iterators`][] for the full API for this iterator type. Raises ------ @@ -5199,7 +5204,7 @@ async def reposition_channels( Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -5250,18 +5255,19 @@ def fetch_members( ) -> iterators.LazyIterator[guilds.Member]: """Fetch the members from a guild. - .. warning:: - This endpoint requires the `GUILD_MEMBERS` intent to be enabled in - the dashboard, not necessarily authenticated with it if using the - gateway. If you don't have the intents you can use `search_members` - which doesn't require any intents. + !!! warning + This endpoint requires the [hikari.intents.Intents.GUILD_MEMBERS] intent + to be enabled in the dashboard, not necessarily authenticated with it + if using the gateway. If you don't have the intents you can use + [`hikari.api.rest.RESTClient.search_members`][] which doesn't require + any intents. - .. note:: + !!! note This call is not a coroutine function, it returns a special type of lazy iterator that will perform API calls as you iterate across it, thus any errors documented below will happen then. - See `hikari.iterators` for the full API for this iterator type. + See [`hikari.iterators`][] for the full API for this iterator type. Parameters ---------- @@ -5291,9 +5297,9 @@ def fetch_members( async def fetch_my_member(self, guild: snowflakes.SnowflakeishOr[guilds.PartialGuild]) -> guilds.Member: """Fetch the Oauth token's associated member in a guild. - .. warning:: + !!! warning This endpoint can only be used with a Bearer token. Using this - with a Bot token will result in a `hikari.errors.UnauthorizedError`. + with a Bot token will result in a [`hikari.errors.UnauthorizedError`][]. Returns ------- @@ -5319,8 +5325,8 @@ async def search_members( ) -> typing.Sequence[guilds.Member]: """Search the members in a guild by nickname and username. - .. note:: - Unlike `RESTClient.fetch_members` this endpoint isn't paginated and + !!! note + Unlike [`hikari.api.rest.RESTClient.fetch_members`][] this endpoint isn't paginated and therefore will return all the members in one go rather than needing to be asynchronously iterated over. @@ -5379,40 +5385,40 @@ async def edit_member( Other Parameters ---------------- nickname : hikari.undefined.UndefinedNoneOr[str] - If provided, the new nick for the member. If `None`, + If provided, the new nick for the member. If [`None`][], will remove the members nick. - Requires the `MANAGE_NICKNAMES` permission. + Requires the [`hikari.permissions.Permissions.MANAGE_NICKNAMES`][] permission. roles : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishSequence[hikari.guilds.PartialRole]] If provided, the new roles for the member. - Requires the `MANAGE_ROLES` permission. + Requires the [`hikari.permissions.Permissions.MANAGE_ROLES`][] permission. mute : hikari.undefined.UndefinedOr[bool] If provided, the new server mute state for the member. - Requires the `MUTE_MEMBERS` permission. + Requires the [`hikari.permissions.Permissions.MUTE_MEMBERS`][] permission. deaf : hikari.undefined.UndefinedOr[bool] If provided, the new server deaf state for the member. - Requires the `DEAFEN_MEMBERS` permission. + Requires the [`hikari.permissions.Permissions.DEAFEN_MEMBERS`][] permission. voice_channel : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.channels.GuildVoiceChannel]]] - If provided, `None` or the object or the ID of + If provided, [`None`][] or the object or the ID of an existing voice channel to move the member to. - If `None`, will disconnect the member from voice. + If [`None`][], will disconnect the member from voice. - Requires the `MOVE_MEMBERS` permission and the `CONNECT` - permission in the original voice channel and the target - voice channel. + Requires the [`hikari.permissions.Permissions.MOVE_MEMBERS`][] permission + and the [`hikari.permissions.Permissions.CONNECT`][] permission in the + original voice channel and the target voice channel. - .. note:: + !!! note If the member is not in a voice channel, this will take no effect. communication_disabled_until : hikari.undefined.UndefinedNoneOr[datetime.datetime] If provided, the datetime when the timeout (disable communication) - of the member expires, up to 28 days in the future, or `None` + of the member expires, up to 28 days in the future, or [`None`][] to remove the timeout from the member. - Requires the `MODERATE_MEMBERS` permission. + Requires the [`hikari.permissions.Permissions.MODERATE_MEMBERS`][] permission. reason : hikari.undefined.UndefinedOr[str] If provided, the reason that will be recorded in the audit logs. Maximum of 512 characters. @@ -5459,9 +5465,9 @@ async def edit_my_member( ---------------- nickname : hikari.undefined.UndefinedNoneOr[str] If provided, the new nickname for the member. If - `None`, will remove the members nickname. + [`None`][], will remove the members nickname. - Requires the `CHANGE_NICKNAME` permission. + Requires the [`hikari.permissions.Permissions.CHANGE_NICKNAME`][] permission. If provided, the reason that will be recorded in the audit logs. Maximum of 512 characters. reason : hikari.undefined.UndefinedOr[str] @@ -5522,7 +5528,7 @@ async def add_role_to_member( Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_ROLES` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_ROLES`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -5566,7 +5572,7 @@ async def remove_role_from_member( Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_ROLES` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_ROLES`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -5606,7 +5612,7 @@ async def kick_user( Raises ------ hikari.errors.ForbiddenError - If you are missing the `KICK_MEMBERS` permission. + If you are missing the [`hikari.permissions.Permissions.KICK_MEMBERS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -5626,7 +5632,7 @@ async def kick_member( *, reason: undefined.UndefinedOr[str] = undefined.UNDEFINED, ) -> None: - """Alias of `kick_user`.""" + """Alias of [`hikari.api.rest.RESTClient.kick_user`][].""" @abc.abstractmethod async def ban_user( @@ -5653,7 +5659,7 @@ async def ban_user( delete_message_seconds : hikari.undefined.UndefinedNoneOr[hikari.internal.time.Intervalish] If provided, the number of seconds to delete messages for. This can be represented as either an int/float between 0 and 604800 (7 days), or - a `datetime.timedelta` object. + a [`datetime.timedelta`][] object. reason : hikari.undefined.UndefinedOr[str] If provided, the reason that will be recorded in the audit logs. Maximum of 512 characters. @@ -5663,7 +5669,7 @@ async def ban_user( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `BAN_MEMBERS` permission. + If you are missing the [`hikari.permissions.Permissions.BAN_MEMBERS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -5684,7 +5690,7 @@ async def ban_member( delete_message_seconds: undefined.UndefinedOr[time.Intervalish] = undefined.UNDEFINED, reason: undefined.UndefinedOr[str] = undefined.UNDEFINED, ) -> None: - """Alias of `ban_user`.""" + """Alias of [`hikari.api.rest.RESTClient.ban_user`][].""" @abc.abstractmethod async def unban_user( @@ -5714,7 +5720,7 @@ async def unban_user( Raises ------ hikari.errors.ForbiddenError - If you are missing the `BAN_MEMBERS` permission. + If you are missing the [`hikari.permissions.Permissions.BAN_MEMBERS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -5734,7 +5740,7 @@ async def unban_member( *, reason: undefined.UndefinedOr[str] = undefined.UNDEFINED, ) -> None: - """Alias of `unban_user`.""" + """Alias of [`hikari.api.rest.RESTClient.unban_user`][].""" @abc.abstractmethod async def fetch_ban( @@ -5759,7 +5765,7 @@ async def fetch_ban( Raises ------ hikari.errors.ForbiddenError - If you are missing the `BAN_MEMBERS` permission. + If you are missing the [`hikari.permissions.Permissions.BAN_MEMBERS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -5783,10 +5789,10 @@ def fetch_bans( ) -> iterators.LazyIterator[guilds.GuildBan]: """Fetch the bans of a guild. - .. note:: + !!! note This call is not a coroutine function, it returns a special type of lazy iterator that will perform API calls as you iterate across it. - See `hikari.iterators` for the full API for this iterator type. + See [`hikari.iterators`][] for the full API for this iterator type. Parameters ---------- @@ -5798,8 +5804,6 @@ def fetch_bans( ---------------- newest_first : bool Whether to fetch the newest first or the oldest first. - - Defaults to `False`. start_at : undefined.UndefinedOr[snowflakes.SearchableSnowflakeishOr[users.PartialUser]] If provided, will start at this snowflake. If you provide a datetime object, it will be transformed into a snowflake. This @@ -5814,7 +5818,7 @@ def fetch_bans( Raises ------ hikari.errors.ForbiddenError - If you are missing the `BAN_MEMBERS` permission. + If you are missing the [`hikari.permissions.Permissions.BAN_MEMBERS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -5915,7 +5919,7 @@ async def create_role( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `MANAGE_ROLES` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_ROLES`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -5946,7 +5950,7 @@ async def reposition_roles( Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_ROLES` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_ROLES`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -6021,7 +6025,7 @@ async def edit_role( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `MANAGE_ROLES` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_ROLES`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -6051,7 +6055,7 @@ async def delete_role( Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_ROLES` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_ROLES`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -6101,7 +6105,7 @@ async def estimate_guild_prune_count( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `KICK_MEMBERS` permission. + If you are missing the [`hikari.permissions.Permissions.KICK_MEMBERS`][] permission. hikari.errors.NotFoundError If the guild is not found. hikari.errors.RateLimitTooLongError @@ -6148,8 +6152,8 @@ async def begin_guild_prune( Returns ------- typing.Optional[int] - If `compute_prune_count` is not provided or `True`, the - number of members pruned. Else `None`. + If `compute_prune_count` is not provided or [`True`][], the + number of members pruned. Else [`None`][]. Raises ------ @@ -6158,7 +6162,7 @@ async def begin_guild_prune( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `KICK_MEMBERS` permission. + If you are missing the [`hikari.permissions.Permissions.KICK_MEMBERS`][] permission. hikari.errors.NotFoundError If the guild is not found. hikari.errors.RateLimitTooLongError @@ -6218,7 +6222,7 @@ async def fetch_guild_invites( Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_GUILD` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -6250,7 +6254,7 @@ async def fetch_integrations( Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_GUILD` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -6280,7 +6284,7 @@ async def fetch_widget(self, guild: snowflakes.SnowflakeishOr[guilds.PartialGuil Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_GUILD` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission. hikari.errors.NotFoundError If the guild is not found. hikari.errors.UnauthorizedError @@ -6312,7 +6316,7 @@ async def edit_widget( Other Parameters ---------------- channel : hikari.undefined.UndefinedNoneOr[hikari.snowflakes.SnowflakeishOr[hikari.channels.GuildChannel]] - If provided, the channel to set the widget to. If `None`, + If provided, the channel to set the widget to. If [`None`][], will not set to any. enabled : hikari.undefined.UndefinedOr[bool] If provided, whether to enable the widget. @@ -6328,7 +6332,7 @@ async def edit_widget( Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_GUILD` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission. hikari.errors.NotFoundError If the guild is not found. hikari.errors.UnauthorizedError @@ -6389,15 +6393,15 @@ async def edit_welcome_screen( ---------------- description : undefined.UndefinedNoneOr[str] If provided, the description to set for the guild's welcome screen. - This may be `None` to unset the description. + This may be [`None`][] to unset the description. enabled : undefined.UndefinedOr[bool] If provided, Whether the guild's welcome screen should be enabled. channels : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.guilds.WelcomeChannel]] If provided, a sequence of up to 5 public channels to set in this - guild's welcome screen. This may be passed as `None` to + guild's welcome screen. This may be passed as [`None`][] to remove all welcome channels - .. note:: + !!! note Custom emojis may only be included in a guild's welcome channels if it's boost status is tier 2 or above. @@ -6414,7 +6418,7 @@ async def edit_welcome_screen( 2 of above boost status or if a private channel is included as a welcome channel. hikari.errors.ForbiddenError - If you are missing the `MANAGE_GUILD` permission, are not part of + If you are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission, are not part of the guild or the guild doesn't have access to the community welcome screen feature. hikari.errors.NotFoundError @@ -6490,7 +6494,7 @@ async def create_template( hikari.errors.ForbiddenError If you are not part of the guild. hikari.errors.NotFoundError - If the guild is not found or you are missing the `MANAGE_GUILD` + If the guild is not found or you are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). @@ -6511,7 +6515,7 @@ async def create_guild_from_template( ) -> guilds.RESTGuild: """Make a guild from a template. - .. note:: + !!! note This endpoint can only be used by bots in less than 10 guilds. Parameters @@ -6525,7 +6529,7 @@ async def create_guild_from_template( ---------------- icon : hikari.undefined.UndefinedOr[hikari.files.Resourceish] If provided, the guild icon to set. Must be a 1024x1024 image or can - be an animated gif when the guild has the `ANIMATED_ICON` feature. + be an animated gif when the guild has the [`hikari.guilds.GuildFeature.ANIMATED_ICON`][] feature. Returns ------- @@ -6569,7 +6573,7 @@ async def delete_template( hikari.errors.ForbiddenError If you are not part of the guild. hikari.errors.NotFoundError - If the guild is not found or you are missing the `MANAGE_GUILD` + If the guild is not found or you are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). @@ -6615,7 +6619,7 @@ async def edit_template( hikari.errors.ForbiddenError If you are not part of the guild. hikari.errors.NotFoundError - If the guild is not found or you are missing the `MANAGE_GUILD` + If the guild is not found or you are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). @@ -6674,7 +6678,7 @@ async def fetch_guild_templates( hikari.errors.ForbiddenError If you are not part of the guild. hikari.errors.NotFoundError - If the guild is not found or are missing the `MANAGE_GUILD` + If the guild is not found or are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). @@ -6706,7 +6710,7 @@ async def sync_guild_template( Raises ------ hikari.errors.ForbiddenError - If you are not part of the guild or are missing the `MANAGE_GUILD` + If you are not part of the guild or are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission. hikari.errors.NotFoundError If the guild or template is not found. @@ -6721,7 +6725,7 @@ async def sync_guild_template( @abc.abstractmethod def slash_command_builder(self, name: str, description: str) -> special_endpoints.SlashCommandBuilder: - r"""Create a command builder to use in `RESTClient.set_application_commands`. + r"""Create a command builder to use in [`hikari.api.rest.RESTClient.set_application_commands`][]. Parameters ---------- @@ -6742,7 +6746,7 @@ def slash_command_builder(self, name: str, description: str) -> special_endpoint def context_menu_command_builder( self, type: typing.Union[commands.CommandType, int], name: str ) -> special_endpoints.ContextMenuCommandBuilder: - r"""Create a command builder to use in `RESTClient.set_application_commands`. + r"""Create a command builder to use in [`hikari.api.rest.RESTClient.set_application_commands`][]. Parameters ---------- @@ -6777,7 +6781,7 @@ async def fetch_application_command( ---------------- guild : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild] Object or ID of the guild to fetch the command for. If left as - `hikari.undefined.UNDEFINED` then this will return a global command, + [`hikari.undefined.UNDEFINED`][] then this will return a global command, otherwise this will return a command made for the specified guild. Returns @@ -6817,7 +6821,7 @@ async def fetch_application_commands( ---------------- guild : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild] Object or ID of the guild to fetch the commands for. If left as - `hikari.undefined.UNDEFINED` then this will only return the global + [`hikari.undefined.UNDEFINED`][] then this will only return the global commands, otherwise this will only return the commands set exclusively for the specific guild. @@ -6881,7 +6885,7 @@ async def create_slash_command( ---------------- guild : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild] Object or ID of the specific guild this should be made for. - If left as `hikari.undefined.UNDEFINED` then this call will create + If left as [`hikari.undefined.UNDEFINED`][] then this call will create a global command rather than a guild specific one. options : hikari.undefined.UndefinedOr[typing.Sequence[hikari.commands.CommandOption]] A sequence of up to 10 options for this command. @@ -6958,7 +6962,7 @@ async def create_context_menu_command( ---------------- guild : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild] Object or ID of the specific guild this should be made for. - If left as `hikari.undefined.UNDEFINED` then this call will create + If left as [`hikari.undefined.UNDEFINED`][] then this call will create a global command rather than a guild specific one. name_localizations : hikari.undefined.UndefinedOr[typing.Mapping[typing.Union[hikari.locales.Locale, str], str]] The name localizations for this command. @@ -7005,7 +7009,7 @@ async def set_application_commands( ) -> typing.Sequence[commands.PartialCommand]: """Set the commands for an application. - .. warning:: + !!! warning Any existing commands not included in the provided commands array will be deleted. @@ -7021,7 +7025,7 @@ async def set_application_commands( ---------------- guild : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild] Object or ID of the specific guild to set the commands for. - If left as `hikari.undefined.UNDEFINED` then this set the global + If left as [`hikari.undefined.UNDEFINED`][] then this set the global commands rather than guild specific commands. Returns @@ -7074,17 +7078,17 @@ async def edit_application_command( ---------------- guild : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild]] Object or ID of the guild to edit a command for if this is a guild - specific command. Leave this as `hikari.undefined.UNDEFINED` to delete + specific command. Leave this as [`hikari.undefined.UNDEFINED`][] to delete a global command. name : hikari.undefined.UndefinedOr[str] - The name to set for the command. Leave as `hikari.undefined.UNDEFINED` + The name to set for the command. Leave as [`hikari.undefined.UNDEFINED`][] to not change. description : hikari.undefined.UndefinedOr[str] - The description to set for the command. Leave as `hikari.undefined.UNDEFINED` + The description to set for the command. Leave as [`hikari.undefined.UNDEFINED`][] to not change. options : hikari.undefined.UndefinedOr[typing.Sequence[hikari.commands.CommandOption]] A sequence of up to 10 options to set for this command. Leave this as - `hikari.undefined.UNDEFINED` to not change. + [`hikari.undefined.UNDEFINED`][] to not change. default_member_permissions : typing.Union[hikari.undefined.UndefinedType, int, hikari.permissions.Permissions] Member permissions necessary to utilize this command by default. @@ -7137,7 +7141,7 @@ async def delete_application_command( ---------------- guild : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild]] Object or ID of the guild to delete a command for if this is a guild - specific command. Leave this as `hikari.undefined.UNDEFINED` to + specific command. Leave this as [`hikari.undefined.UNDEFINED`][] to delete a global command. Raises @@ -7239,13 +7243,14 @@ async def set_application_command_permissions( ) -> commands.GuildCommandPermissions: """Set permissions for a specific command. - .. note:: + !!! note This requires the `access_token` to have the - `hikari.applications.OAuth2Scope.APPLICATIONS_COMMANDS_PERMISSION_UPDATE` - scope enabled along with the authorization of a Bot which has `MANAGE_INVITES` - permission within the target guild. + [`hikari.applications.OAuth2Scope.APPLICATIONS_COMMANDS_PERMISSION_UPDATE`][] + scope enabled along with the authorization of a Bot which has + [`hikari.permissions.Permissions.CREATE_INSTANT_INVITE`][] permission + within the target guild. - .. note:: + !!! note This overwrites any previously set permissions. Parameters @@ -7302,6 +7307,8 @@ def interaction_autocomplete_builder( ) -> special_endpoints.InteractionAutocompleteBuilder: """Create a builder for an autocomplete interaction response. + Parameters + ---------- choices : typing.Sequence[hikari.api.special_endpoints.AutocompleteChoiceBuilder] The autocomplete choices. @@ -7406,9 +7413,9 @@ async def create_interaction_response( ) -> None: """Create the initial response for a interaction. - .. warning:: + !!! warning Calling this with an interaction which already has an initial - response will result in this raising a `hikari.errors.NotFoundError`. + response will result in this raising a [`hikari.errors.NotFoundError`][]. This includes if the REST interaction server has already responded to the request. @@ -7425,11 +7432,11 @@ async def create_interaction_response( ---------------- content : hikari.undefined.UndefinedOr[typing.Any] If provided, the message contents. If - `hikari.undefined.UNDEFINED`, then nothing will be sent + [`hikari.undefined.UNDEFINED`][], then nothing will be sent in the content. Any other value here will be cast to a - `str`. + [`str`][]. - If this is a `hikari.embeds.Embed` and no `embed` nor + If this is a [`hikari.embeds.Embed`][] and no `embed` nor no `embeds` kwarg is provided, then this will instead update the embed. This allows for simpler syntax when sending an embed alone. @@ -7452,8 +7459,8 @@ async def create_interaction_response( If provided, the message flags this response should have. As of writing the only message flags which can be set here are - `hikari.messages.MessageFlag.EPHEMERAL`, `hikari.messages.MessageFlag.SUPPRESS_NOTIFICATIONS` - and `hikari.messages.MessageFlag.SUPPRESS_EMBEDS`. + [`hikari.messages.MessageFlag.EPHEMERAL`][], [`hikari.messages.MessageFlag.SUPPRESS_NOTIFICATIONS`][] + and [`hikari.messages.MessageFlag.SUPPRESS_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. @@ -7461,20 +7468,20 @@ async def create_interaction_response( If provided, whether the message should parse @everyone/@here mentions. 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 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 + [`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 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 + [`hikari.snowflakes.Snowflake`][], or + [`hikari.guilds.PartialRole`][] derivatives to enforce mentioning specific roles. Raises @@ -7530,7 +7537,7 @@ async def edit_interaction_response( ) -> messages_.Message: """Edit the initial response to a command interaction. - .. note:: + !!! note Mentioning everyone, roles, or users in message edits currently will not send a push notification showing a new mention to people on Discord. It will still highlight in their chat as if they @@ -7538,7 +7545,7 @@ async def edit_interaction_response( Also important to note that if you specify a text `content`, `mentions_everyone`, `mentions_reply`, `user_mentions`, and `role_mentions` will default - to `False` as the message will be re-parsed for mentions. This will + to [`False`][] as the message will be re-parsed for mentions. This will also occur if only one of the four are specified This is a limitation of Discord's design. If in doubt, specify all @@ -7555,68 +7562,68 @@ async def edit_interaction_response( ---------------- content : hikari.undefined.UndefinedOr[typing.Any] If provided, the message content to update with. If - `hikari.undefined.UNDEFINED`, then the content will not - be changed. If `None`, then the content will be removed. + [`hikari.undefined.UNDEFINED`][], then the content will not + be changed. If [`None`][], then the content will be removed. - Any other value will be cast to a `str` before sending. + Any other value will be cast to a [`str`][] before sending. - If this is a `hikari.embeds.Embed` and neither the + If this is a [`hikari.embeds.Embed`][] and neither the `embed` or `embeds` kwargs are provided or if this is a - `hikari.files.Resourceish` and neither the `attachment` or + [`hikari.files.Resourceish`][] and neither the `attachment` or `attachments` kwargs are provided, the values will be overwritten. This allows for simpler syntax when sending an embed or an attachment alone. attachment : hikari.undefined.UndefinedNoneOr[typing.Union[hikari.files.Resourceish, hikari.messages.Attachment]] If provided, the attachment to set on the message. If - `hikari.undefined.UNDEFINED`, the previous attachment, if - present, is not changed. If this is `None`, then the + [`hikari.undefined.UNDEFINED`][], the previous attachment, if + present, is not changed. If this is [`None`][], then the attachment is removed, if present. Otherwise, the new attachment that was provided will be attached. attachments : hikari.undefined.UndefinedNoneOr[typing.Sequence[typing.Union[hikari.files.Resourceish, hikari.messages.Attachment]]] If provided, the attachments to set on the message. If - `hikari.undefined.UNDEFINED`, the previous attachments, if - present, are not changed. If this is `None`, then the + [`hikari.undefined.UNDEFINED`][], the previous attachments, if + present, are not changed. If this is [`None`][], then the attachments is removed, if present. Otherwise, the new attachments that were provided will be attached. component : hikari.undefined.UndefinedNoneOr[hikari.api.special_endpoints.ComponentBuilder] If provided, builder object of the component to set for this message. This component will replace any previously set components and passing - `None` will remove all components. + [`None`][] will remove all components. components : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.api.special_endpoints.ComponentBuilder]] If provided, a sequence of the component builder objects set for this message. These components will replace any previously set - components and passing `None` or an empty sequence will + components and passing [`None`][] or an empty sequence will remove all components. embed : hikari.undefined.UndefinedNoneOr[hikari.embeds.Embed] If provided, the embed to set on the message. If - `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed. - If this is `None` then any present embeds are removed. + [`hikari.undefined.UNDEFINED`][], the previous embed(s) are not changed. + If this is [`None`][] then any present embeds are removed. Otherwise, the new embed that was provided will be used as the replacement. embeds : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.embeds.Embed]] If provided, the embeds to set on the message. If - `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed. - If this is `None` then any present embeds are removed. + [`hikari.undefined.UNDEFINED`][], the previous embed(s) are not changed. + If this is [`None`][] then any present embeds are removed. Otherwise, the new embeds that were provided will be used as the replacement. mentions_everyone : hikari.undefined.UndefinedOr[bool] If provided, whether the message should parse @everyone/@here mentions. 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 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 + [`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 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 + [`hikari.snowflakes.Snowflake`][], or + [`hikari.guilds.PartialRole`][] derivatives to enforce mentioning specific roles. Returns @@ -7790,8 +7797,8 @@ async def fetch_scheduled_event( hikari.errors.ForbiddenError If you are missing the permission needed to view this event. - For `VOICE` and `STAGE_CHANNEL` events, `VIEW_CHANNEL` is required - in their associated guild to see the event. + For `VOICE` and `STAGE_CHANNEL` events, [`hikari.permissions.Permissions.VIEW_CHANNEL`][] + is required in their associated guild to see the event. hikari.errors.NotFoundError If the guild or event is not found. hikari.errors.RateLimitTooLongError @@ -7807,7 +7814,7 @@ async def fetch_scheduled_events( ) -> typing.Sequence[scheduled_events.ScheduledEvent]: """Fetch the scheduled events for a guild. - .. note:: + !!! note `VOICE` and `STAGE_CHANNEL` events are only included if the bot has `VOICE` or `STAGE_CHANNEL` permissions in the associated channel. @@ -7895,7 +7902,9 @@ async def create_stage_event( If you are missing permissions to create the scheduled event. You need the following permissions in the target stage channel: - `MANAGE_EVENTS`, `VIEW_CHANNEL` and `CONNECT`. + [`hikari.permissions.Permissions.MANAGE_EVENTS`][], + [`hikari.permissions.Permissions.VIEW_CHANNEL`][], + and [`hikari.permissions.Permissions.CONNECT`][]. hikari.errors.NotFoundError If the guild or event is not found. hikari.errors.RateLimitTooLongError @@ -7966,7 +7975,9 @@ async def create_voice_event( If you are missing permissions to create the scheduled event. You need the following permissions in the target voice channel: - `MANAGE_EVENTS`, `VIEW_CHANNEL` and `CONNECT`. + [`hikari.permissions.Permissions.MANAGE_EVENTS`][], + [`hikari.permissions.Permissions.VIEW_CHANNEL`][], + and [`hikari.permissions.Permissions.CONNECT`][]. hikari.errors.NotFoundError If the guild or event is not found. hikari.errors.RateLimitTooLongError @@ -8034,7 +8045,7 @@ async def create_external_event( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_EVENTS` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_EVENTS`][] permission. hikari.errors.NotFoundError If the guild or event is not found. hikari.errors.RateLimitTooLongError @@ -8101,7 +8112,7 @@ async def edit_scheduled_event( end_time : hikari.undefined.UndefinedNoneOr[datetime.datetime] When the event should be scheduled to end. - This can only be set to `None` for `STAGE` and `VOICE` events. + This can only be set to [`None`][] for `STAGE` and `VOICE` events. Must be provided when changing an event to `EXTERNAL`. status : hikari.undefined.UndefinedOr[hikari.scheduled_events.ScheduledEventStatus] The event's new status. @@ -8127,10 +8138,10 @@ async def edit_scheduled_event( If you are missing permissions to edit the scheduled event. For `VOICE` and `STAGE_INSTANCE` events, you need the following - permissions in the event's associated channel: `MANAGE_EVENTS`, - `VIEW_CHANNEL` and `CONNECT`. + permissions in the event's associated channel: [`hikari.permissions.Permissions.MANAGE_EVENTS`][], + [`hikari.permissions.Permissions.VIEW_CHANNEL`][] and [`hikari.permissions.Permissions.CONNECT`][]. - For `EXTERNAL` events you just need the `MANAGE_EVENTS` permission. + For `EXTERNAL` events you just need the [`hikari.permissions.Permissions.MANAGE_EVENTS`][] permission. hikari.errors.NotFoundError If the guild or event is not found. hikari.errors.RateLimitTooLongError @@ -8161,7 +8172,7 @@ async def delete_scheduled_event( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_EVENTS` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_EVENTS`][] permission. hikari.errors.NotFoundError If the guild or event is not found. hikari.errors.RateLimitTooLongError @@ -8183,12 +8194,12 @@ def fetch_scheduled_event_users( ) -> iterators.LazyIterator[scheduled_events.ScheduledEventUser]: """Asynchronously iterate over the users who're subscribed to a scheduled event. - .. note:: + !!! note This call is not a coroutine function, it returns a special type of lazy iterator that will perform API calls as you iterate across it, thus any errors documented below will happen then. - See `hikari.iterators` for the full API for this iterator type. + See [`hikari.iterators`][] for the full API for this iterator type. Parameters ---------- @@ -8201,8 +8212,6 @@ def fetch_scheduled_event_users( ---------------- newest_first : bool Whether to fetch the newest first or the oldest first. - - Defaults to `False`. start_at : hikari.undefined.UndefinedOr[hikari.snowflakes.SearchableSnowflakeishOr[hikari.guilds.PartialGuild]] If provided, will start at this snowflake. If you provide a datetime object, it will be transformed into a snowflake. This diff --git a/hikari/api/shard.py b/hikari/api/shard.py index b0378a880c..21d53511e8 100644 --- a/hikari/api/shard.py +++ b/hikari/api/shard.py @@ -151,8 +151,7 @@ async def update_presence( The datetime that the user started being idle. If undefined, this will not be changed. afk : hikari.undefined.UndefinedOr[bool] - If `True`, the user is marked as AFK. If `False`, - the user is marked as being active. If undefined, this will not be + Whether to mark the user as AFK. If undefined, this will not be changed. activity : hikari.undefined.UndefinedNoneOr[hikari.presences.Activity] The activity to appear to be playing. If undefined, this will not be @@ -177,15 +176,15 @@ async def update_voice_state( guild : hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild] The guild or guild ID to update the voice state for. channel : typing.Optional[hikari.snowflakes.SnowflakeishOr[hikari.channels.GuildVoiceChannel]] - The channel or channel ID to update the voice state for. If `None` + The channel or channel ID to update the voice state for. If [`None`][] then the bot will leave the voice channel that it is in for the given guild. self_mute : bool - If specified and `True`, the bot will mute itself in that - voice channel. If `False`, then it will unmute itself. + If specified and [`True`][], the bot will mute itself in that + voice channel. If [`False`][], then it will unmute itself. self_deaf : bool - If specified and `True`, the bot will deafen itself in that - voice channel. If `False`, then it will undeafen itself. + If specified and [`True`][], the bot will deafen itself in that + voice channel. If [`False`][], then it will undeafen itself. """ @abc.abstractmethod @@ -201,7 +200,7 @@ async def request_guild_members( ) -> None: """Request for a guild chunk. - .. note:: + !!! note To request the full list of members, set `query` to `""` (empty string) and `limit` to `0`. @@ -226,9 +225,9 @@ async def request_guild_members( Raises ------ ValueError - When trying to specify `users` with `query`/`limit`, if `limit` is not between + If trying to specify `users` with `query`/`limit`, if `limit` is not between 0 and 100, both inclusive or if `users` length is over 100. hikari.errors.MissingIntentError - When trying to request presences without the `GUILD_MEMBERS` or when trying to - request the full list of members without `GUILD_PRESENCES`. + When trying to request presences without the [`hikari.intents.Intents.GUILD_MEMBERS`][] or when trying to + request the full list of members without [`hikari.intents.Intents.GUILD_PRESENCES`][]. """ diff --git a/hikari/api/special_endpoints.py b/hikari/api/special_endpoints.py index f6261f1fe6..80059de448 100644 --- a/hikari/api/special_endpoints.py +++ b/hikari/api/special_endpoints.py @@ -81,14 +81,14 @@ class TypingIndicator(abc.ABC): - """Result type of `hikari.api.rest.RESTClient.trigger_typing`. + """Result type of [`hikari.api.rest.RESTClient.trigger_typing`][]. This is an object that can either be awaited like a coroutine to trigger the typing indicator once, or an async context manager to keep triggering the typing indicator repeatedly until the context finishes. - .. note:: - This is a helper class that is used by `hikari.api.rest.RESTClient`. + !!! note + This is a helper class that is used by [`hikari.api.rest.RESTClient`][]. You should only ever need to use instances of this class that are produced by that API. """ @@ -111,19 +111,19 @@ async def __aexit__( class GuildBuilder(abc.ABC): - """Result type of `hikari.api.rest.RESTClient.guild_builder`. + """Result type of [`hikari.api.rest.RESTClient.guild_builder`][]. This is used to create a guild in a tidy way using the HTTP API, since the logic behind creating a guild on an API level is somewhat confusing and detailed. - .. note:: - If you call `add_role`, the default roles provided by Discord will + !!! note + If you call [`hikari.api.special_endpoints.GuildBuilder.add_role`][], the default roles provided by Discord will be created. This also applies to the `add_` functions for text channels/voice channels/categories. - .. note:: - Functions that return a `hikari.snowflakes.Snowflake` do + !!! note + Functions that return a [`hikari.snowflakes.Snowflake`][] do **not** provide the final ID that the object will have once the API call is made. The returned IDs are only able to be used to re-reference particular objects while building the guild format @@ -134,24 +134,23 @@ class GuildBuilder(abc.ABC): -------- Creating an empty guild: - .. code-block:: python - + ```py guild = await rest.guild_builder("My Server!").create() + ``` Creating a guild with an icon: - .. code-block:: python - + ```py from hikari.files import WebResourceStream guild_builder = rest.guild_builder("My Server!") guild_builder.icon = WebResourceStream("cat.png", "http://...") guild = await guild_builder.create() + ``` Adding roles to your guild: - .. code-block:: python - + ```py from hikari.permissions import Permissions guild_builder = rest.guild_builder("My Server!") @@ -160,20 +159,21 @@ class GuildBuilder(abc.ABC): admin_role_id = guild_builder.add_role("Admins", permissions=Permissions.ADMINISTRATOR) await guild_builder.create() + ``` - .. warning:: + !!! warning The first role must always be the `@everyone` role. Adding a text channel to your guild: - .. code-block:: python - + ```py guild_builder = rest.guild_builder("My Server!") category_id = guild_builder.add_category("My safe place") channel_id = guild_builder.add_text_channel("general", parent_id=category_id) await guild_builder.create() + ``` """ __slots__: typing.Sequence[str] = () @@ -274,8 +274,9 @@ def add_role( ) -> snowflakes.Snowflake: """Create a role. - .. warning:: - The first role you create must always be the `@everyone` role. + !!! warning + The first role you create (i.e., position 0) must always be the + `@everyone` role. Parameters ---------- @@ -294,6 +295,8 @@ def add_role( If provided, whether to hoist the role. mentionable : hikari.undefined.UndefinedOr[bool] If provided, whether to make the role mentionable. + position : hikari.undefined.UndefinedOr[int] + If provided, the position of the role. Returns ------- @@ -440,7 +443,7 @@ def add_voice_channel( If provided, the permission overwrites for the channel. region : hikari.undefined.UndefinedOr[typing.Union[hikari.voices.VoiceRegion, str]] If provided, the voice region to for this channel. Passing - `None` here will set it to "auto" mode where the used + [`None`][] here will set it to "auto" mode where the used region will be decided based on the first person who connects to it when it's empty. parent_id : hikari.undefined.UndefinedOr[hikari.snowflakes.Snowflake] @@ -494,7 +497,7 @@ def add_stage_channel( If provided, the permission overwrites for the channel. region : hikari.undefined.UndefinedOr[typing.Union[hikari.voices.VoiceRegion, str]] If provided, the voice region to for this channel. Passing - `None` here will set it to "auto" mode where the used + [`None`][] here will set it to "auto" mode where the used region will be decided based on the first person who connects to it when it's empty. parent_id : hikari.undefined.UndefinedOr[hikari.snowflakes.Snowflake] @@ -555,20 +558,20 @@ def type(self) -> base_interactions.DeferredResponseTypesT: def flags(self) -> typing.Union[undefined.UndefinedType, int, messages.MessageFlag]: """Message flags this response should have. - .. note:: + !!! note As of writing the only message flags which can be set here are - `hikari.messages.MessageFlag.EPHEMERAL`, `hikari.messages.MessageFlag.SUPPRESS_NOTIFICATIONS` - and `hikari.messages.MessageFlag.SUPRESS_EMBEDS`. + [`hikari.messages.MessageFlag.EPHEMERAL`][], [`hikari.messages.MessageFlag.SUPPRESS_NOTIFICATIONS`][] + and [`hikari.messages.MessageFlag.SUPPRESS_EMBEDS`][]. """ @abc.abstractmethod def set_flags(self, flags: typing.Union[undefined.UndefinedType, int, messages.MessageFlag], /) -> Self: """Set message flags for this response. - .. note:: - As of writing, the only message flags which can be set are `hikari.messages.MessageFlag.EPHEMERAL` - `hikari.messages.MessageFlag.SUPPRESS_NOTIFICATIONS` and - `hikari.messages.MessageFlag.SUPRESS_EMBEDS`. + !!! note + As of writing, the only message flags which can be set are [`hikari.messages.MessageFlag.EPHEMERAL`][] + [`hikari.messages.MessageFlag.SUPPRESS_NOTIFICATIONS`][] and + [`hikari.messages.MessageFlag.SUPPRESS_EMBEDS`][]. Parameters ---------- @@ -658,7 +661,7 @@ class InteractionMessageBuilder(InteractionResponseBuilder, abc.ABC): """Interface of an interaction message response builder used within REST servers. This can be returned by the listener registered to - `hikari.api.interaction_server.InteractionServer` as a response to the interaction + [`hikari.api.interaction_server.InteractionServer`][] as a response to the interaction create. """ @@ -700,11 +703,11 @@ def content(self) -> undefined.UndefinedNoneOr[str]: def flags(self) -> typing.Union[undefined.UndefinedType, int, messages.MessageFlag]: """Message flags this response should have. - .. note:: + !!! note As of writing the only message flags which can be set here are - `hikari.messages.MessageFlag.EPHEMERAL`, - `hikari.messages.MessageFlag.SUPPRESS_NOTIFICATIONS` - and `hikari.messages.MessageFlag.SUPRESS_EMBEDS`. + [`hikari.messages.MessageFlag.EPHEMERAL`][], + [`hikari.messages.MessageFlag.SUPPRESS_NOTIFICATIONS`][] + and [`hikari.messages.MessageFlag.SUPPRESS_EMBEDS`][]. """ @property @@ -725,8 +728,8 @@ def role_mentions( """Whether and what role mentions should be enabled for this response. Either a sequence of object/IDs of the roles mentions should be enabled - for, `False` or `hikari.undefined.UNDEFINED` to disallow any - role mentions or `True` to allow all role mentions. + for, [`False`][] or [`hikari.undefined.UNDEFINED`][] to disallow any + role mentions or [`True`][] to allow all role mentions. """ @property @@ -737,8 +740,8 @@ def user_mentions( """Whether and what user mentions should be enabled for this response. Either a sequence of object/IDs of the users mentions should be enabled - for, `False` or `hikari.undefined.UNDEFINED` to disallow any - user mentions or `True` to allow all user mentions. + for, [`False`][] or [`hikari.undefined.UNDEFINED`][] to disallow any + user mentions or [`True`][] to allow all user mentions. """ @abc.abstractmethod @@ -818,9 +821,9 @@ def set_content(self, content: undefined.UndefinedOr[str], /) -> Self: def set_flags(self, flags: typing.Union[undefined.UndefinedType, int, messages.MessageFlag], /) -> Self: """Set message flags for this response. - .. note:: + !!! note As of writing, the only message flags which can be set is - `hikari.messages.MessageFlag.EPHEMERAL` and `hikari.messages.MessageFlag.SUPPRESS_NOTIFICATIONS`.. + [`hikari.messages.MessageFlag.EPHEMERAL`][] and [`hikari.messages.MessageFlag.SUPPRESS_NOTIFICATIONS`][]. Parameters ---------- @@ -877,8 +880,8 @@ def set_role_mentions( ---------- mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.users.PartialUser], bool]] Either a sequence of object/IDs of the roles mentions should be enabled for, - `False` or `hikari.undefined.UNDEFINED` to disallow any role - mentions or `True` to allow all role mentions. + [`False`][] or [`hikari.undefined.UNDEFINED`][] to disallow any role + mentions or [`True`][] to allow all role mentions. Returns ------- @@ -900,8 +903,8 @@ def set_user_mentions( ---------- mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.users.PartialUser], bool]] Either a sequence of object/IDs of the users mentions should be enabled for, - `False` or `hikari.undefined.UNDEFINED` to disallow any user - mentions or `True` to allow all user mentions. + [`False`][] or [`hikari.undefined.UNDEFINED`][] to disallow any user + mentions or [`True`][] to allow all user mentions. Returns ------- @@ -914,7 +917,7 @@ class InteractionModalBuilder(InteractionResponseBuilder, abc.ABC): """Interface of an interaction modal response builder used within REST servers. This can be returned by the listener registered to - `hikari.api.interaction_server.InteractionServer` as a response to the interaction + [`hikari.api.interaction_server.InteractionServer`][] as a response to the interaction create. """ @@ -981,7 +984,7 @@ class CommandBuilder(abc.ABC): def name(self) -> str: r"""Name to set for this command. - .. warning:: + !!! warning This should match the regex `^[-_\p{L}\p{N}\p{sc=Deva}\p{sc=Thai}]{1,32}$` in Unicode mode and must be lowercase. """ @@ -1177,7 +1180,7 @@ class SlashCommandBuilder(CommandBuilder): def description(self) -> str: """Command's description. - .. warning:: + !!! warning This should be inclusively between 1-100 characters in length. """ @@ -1227,7 +1230,7 @@ def set_description_localizations( def add_option(self, option: commands.CommandOption) -> Self: """Add an option to this command. - .. note:: + !!! note A command can have up to 25 options. Parameters @@ -1252,7 +1255,7 @@ async def create( ) -> commands.SlashCommand: """Create this command through a REST call. - This is a shorthand for calling `hikari.api.rest.RESTClient.create_slash_command` + This is a shorthand for calling [`hikari.api.rest.RESTClient.create_slash_command`][] with the builder's information. Parameters @@ -1293,7 +1296,7 @@ async def create( """Create this command through a REST call. This is a shorthand for calling - `hikari.api.rest.RESTClient.create_context_menu_command` + [`hikari.api.rest.RESTClient.create_context_menu_command`][] with the builder's information. Parameters @@ -1363,7 +1366,7 @@ def emoji(self) -> typing.Union[snowflakes.Snowflakeish, emojis.Emoji, str, unde def label(self) -> undefined.UndefinedOr[str]: """Text label which should appear on this button. - .. note:: + !!! note The text label to that should appear on this button. This may be up to 80 characters long. """ @@ -1609,7 +1612,7 @@ def min_values(self) -> int: """Minimum number of options which must be chosen. Defaults to 1. - Must be less than or equal to `SelectMenuBuilder.max_values` and greater + Must be less than or equal to [`hikari.api.special_endpoints.SelectMenuBuilder.max_values`][] and greater than or equal to 0. """ @@ -1619,7 +1622,7 @@ def max_values(self) -> int: """Maximum number of options which can be chosen. Defaults to 1. - Must be greater than or equal to `SelectMenuBuilder.min_values` and + Must be greater than or equal to [`hikari.api.special_endpoints.SelectMenuBuilder.min_values`][] and less than or equal to 25. """ @@ -1642,8 +1645,6 @@ def set_custom_id(self, custom_id: str, /) -> Self: def set_is_disabled(self, state: bool, /) -> Self: """Set whether this option is disabled. - Defaults to `False`. - Parameters ---------- state : bool @@ -1675,9 +1676,9 @@ def set_placeholder(self, value: undefined.UndefinedOr[str], /) -> Self: def set_min_values(self, value: int, /) -> Self: """Set the minimum amount of options which need to be selected for this menu. - .. note:: + !!! note This defaults to 1 if not set and must be greater than or equal to 0 - and less than or equal to `SelectMenuBuilder.max_values`. + and less than or equal to [`hikari.api.special_endpoints.SelectMenuBuilder.max_values`][]. Parameters ---------- @@ -1694,9 +1695,9 @@ def set_min_values(self, value: int, /) -> Self: def set_max_values(self, value: int, /) -> Self: """Set the maximum amount of options which can be selected for this menu. - .. note:: + !!! note This defaults to 1 if not set and must be less than or equal to 25 - and greater than or equal to `SelectMenuBuilder.min_values`. + and greater than or equal to [`hikari.api.special_endpoints.SelectMenuBuilder.min_values`][]. Parameters ---------- @@ -1801,7 +1802,7 @@ def type(self) -> typing.Literal[components_.ComponentType.TEXT_INPUT]: def custom_id(self) -> str: """Developer set custom ID used for identifying this text input. - .. note:: + !!! note This custom_id is never used in component interaction events. It is meant to be used purely for resolving components modal interactions. """ @@ -1981,10 +1982,11 @@ def components(self) -> typing.Sequence[ComponentBuilder]: def add_component(self, component: ComponentBuilder, /) -> Self: """Add a component to this action row builder. - .. warning:: - It is generally better to use `ActionRowBuilder.add_button` - and `ActionRowBuilder.add_select_menu` to add your - component to the builder. Those methods utilize this one. + !!! warning + It is generally better to use + [`hikari.api.special_endpoints.MessageActionRowBuilder.add_interactive_button`][] + and [`hikari.api.special_endpoints.MessageActionRowBuilder.add_select_menu`][] + to add your component to the builder. Those methods utilize this one. Parameters ---------- @@ -2080,8 +2082,8 @@ def add_select_menu( """Add a select menu component to this action row builder. For channel select menus and text select menus see - `MessageActionRowBuilder.add_channel_menu` and - `MessageActionRowBuilder.add_text_menu`. + [`hikari.api.special_endpoints.MessageActionRowBuilder.add_channel_menu`][] + and [`hikari.api.special_endpoints.MessageActionRowBuilder.add_text_menu`][]. Parameters ---------- @@ -2186,9 +2188,9 @@ def add_text_menu( TextSelectMenuBuilder The text select menu builder. - `TextSelectMenuBuilder.add_option` should be called to add + [`hikari.api.special_endpoints.TextSelectMenuBuilder.add_option`][] should be called to add options to the returned builder then - `TextSelectMenuBuilder.parent` can be used to return to this + [`hikari.api.special_endpoints.TextSelectMenuBuilder.parent`][] can be used to return to this action row while chaining calls. Raises @@ -2217,10 +2219,11 @@ def components(self) -> typing.Sequence[ComponentBuilder]: def add_component(self, component: ComponentBuilder, /) -> Self: """Add a component to this action row builder. - .. warning:: - It is generally better to use `ActionRowBuilder.add_button` - and `ActionRowBuilder.add_select_menu` to add your - component to the builder. Those methods utilize this one. + !!! warning + It is generally better to use + [`hikari.api.special_endpoints.MessageActionRowBuilder.add_interactive_button`][] + and [`hikari.api.special_endpoints.MessageActionRowBuilder.add_select_menu`][] + to add your component to the builder. Those methods utilize this one. Parameters ---------- diff --git a/hikari/api/voice.py b/hikari/api/voice.py index f8985fb6ca..0efbed077c 100644 --- a/hikari/api/voice.py +++ b/hikari/api/voice.py @@ -61,8 +61,8 @@ async def close(self) -> None: Once this is done, unsubscribe from any events. - If you simply wish to disconnect every connection, use `disconnect` - instead. + If you simply wish to disconnect every connection, use + [`hikari.api.VoiceComponent.disconnect`][] instead. """ @abc.abstractmethod @@ -101,26 +101,26 @@ async def connect_to( The channel or channel ID to connect to. voice_connection_type : typing.Type[VoiceConnection] The type of voice connection to use. This should be initialized - internally using the `VoiceConnection.initialize` - `classmethod`. + internally using the [`hikari.api.voice.VoiceConnection.initialize`][] + classmethod. deaf : bool - Defaulting to `False`, if `True`, the client will - enter the voice channel deafened (thus unable to hear other users). + If [`True`][], the client will enter the voice channel deafened + (thus unable to hear other users). mute : bool - Defaulting to `False`, if `True`, the client will - enter the voice channel muted (thus unable to send audio). + If [`True`][], the client will enter the voice channel muted + (thus unable to send audio). timeout : typing.Optional[int] - Defaulting to `5`, The amount of time to wait before erroring when - connecting to the voice channel. If timeout is `None` there will be + The amount of time, in seconds, to wait before erroring when + connecting to the voice channel. If timeout is [`None`][] there will be no timeout. - .. warning:: - If timeout is `None`, this function will be awaited forever if an + !!! warning + If timeout is [`None`][], this function will be awaited forever if an invalid `guild_id` or `channel_id` is provided. **kwargs : typing.Any - Any arguments to provide to the `VoiceConnection.initialize` - method. + Any arguments to provide to the + [`hikari.api.voice.VoiceConnection.initialize`][] method. Returns ------- @@ -169,7 +169,7 @@ async def initialize( The channel ID that the voice connection is actively connected to. endpoint : str The voice websocket endpoint to connect to. Will contain the - protocol at the start (i.e. `wss://`), and end with the **correct** + protocol at the start (i.e. [wss://][]), and end with the **correct** port (the port and protocol are sanitized since Discord still provide the wrong information four years later). guild_id : hikari.snowflakes.Snowflake diff --git a/hikari/applications.py b/hikari/applications.py index c6d62272a9..988e400df3 100644 --- a/hikari/applications.py +++ b/hikari/applications.py @@ -108,38 +108,38 @@ class OAuth2Scope(str, enums.Enum): """OAuth2 Scopes that Discord allows. These are categories of permissions for applications using the OAuth2 API - directly. Most users will only ever need the `BOT` scope when developing + directly. Most users will only ever need the [`hikari.applications.OAuth2Scope.BOT`][] scope when developing bots. """ ACTIVITIES_READ = "activities.read" """Enables fetching the "Now Playing/Recently Played" list. - .. note:: + !!! note You must be whitelisted to use this scope. """ ACTIVITIES_WRITE = "activities.write" """Enables updating a user's activity. - .. note:: + !!! note You must be whitelisted to use this scope. - .. note:: + !!! note This is not required to use the GameSDK activity manager. """ APPLICATIONS_BUILDS_READ = "applications.builds.read" """Enables reading build data for a user's applications. - .. note:: + !!! note You must be whitelisted to use this scope. """ APPLICATIONS_BUILDS_UPLOAD = "applications.builds.upload" """Enables uploading/updating builds for a user's applications. - .. note:: + !!! note You must be whitelisted to use this scope. """ @@ -147,7 +147,7 @@ class OAuth2Scope(str, enums.Enum): """Allows your application's commands to be used in a guild. This is used in Discord's special Bot Authorization Flow like - `OAuth2Scope.BOT` in-order to join an application into a guild as an + [`hikari.applications.OAuth2Scope.BOT`][] in-order to join an application into a guild as an application command providing integration. """ @@ -165,14 +165,14 @@ class OAuth2Scope(str, enums.Enum): This includes store listings, achievements, SKU's, etc. - .. note:: + !!! note The store API is deprecated and may be removed in the future. """ BOT = "bot" """Enables adding a bot application to a guild. - .. note:: + !!! note This requires you to have set up a bot account for your application. """ @@ -185,7 +185,7 @@ class OAuth2Scope(str, enums.Enum): GROUP_DM_JOIN = "gdm.join" """Enables joining users into a group DM. - .. warning:: + !!! warning This cannot add the bot to a group DM. """ @@ -195,29 +195,29 @@ class OAuth2Scope(str, enums.Enum): GUILDS_JOIN = "guilds.join" """Enables adding the user to a specific guild. - .. note:: + !!! note This requires you to have set up a bot account for your application. """ IDENTIFY = "identify" """Enables viewing info about itself. - .. note:: - This does not include email address info. Use the `EMAIL` scope instead + !!! note + This does not include email address info. Use the [`hikari.applications.OAuth2Scope.EMAIL`][] scope instead to retrieve this information. """ RELATIONSHIPS_READ = "relationships.read" """Enables viewing a user's friend list. - .. note:: + !!! note You must be whitelisted to use this scope. """ RPC = "rpc" """Enables the RPC application to control the local user's Discord client. - .. note:: + !!! note You must be whitelisted to use this scope. """ @@ -227,7 +227,7 @@ class OAuth2Scope(str, enums.Enum): RPC_NOTIFICATIONS_READ = "rpc.notifications.read" """Enables the RPC application to read from all channels the user is in. - .. note:: + !!! note You must be whitelisted to use this scope. """ @@ -260,13 +260,13 @@ class ConnectionVisibility(int, enums.Enum): class OwnConnection: """Represents a user's connection with a third party account. - Returned by the `GET Current User Connections` endpoint. + Returned by the [GET Current User Connections][] endpoint. """ id: str = attrs.field(hash=True, repr=True) """The string ID of the third party connected account. - .. warning:: + !!! warning Seeing as this is a third party ID, it will not be a snowflakes. """ @@ -277,19 +277,19 @@ class OwnConnection: """The type of service this connection is for.""" is_revoked: bool = attrs.field(eq=False, hash=False, repr=False) - """`True` if the connection has been revoked.""" + """[`True`][] if the connection has been revoked.""" integrations: typing.Sequence[guilds.PartialIntegration] = attrs.field(eq=False, hash=False, repr=False) """A sequence of the partial guild integration objects this connection has.""" is_verified: bool = attrs.field(eq=False, hash=False, repr=False) - """`True` if the connection has been verified.""" + """[`True`][] if the connection has been verified.""" is_friend_sync_enabled: bool = attrs.field(eq=False, hash=False, repr=False) - """`True` if friends should be added based on this connection.""" + """[`True`][] if friends should be added based on this connection.""" is_activity_visible: bool = attrs.field(eq=False, hash=False, repr=False) - """`True` if this connection's activities are shown in the user's presence.""" + """[`True`][] if this connection's activities are shown in the user's presence.""" visibility: typing.Union[ConnectionVisibility, int] = attrs.field(eq=False, hash=False, repr=True) """The visibility of the connection.""" @@ -303,7 +303,7 @@ class OwnGuild(guilds.PartialGuild): """A list of the features in this guild.""" is_owner: bool = attrs.field(eq=False, hash=False, repr=True) - """`True` when the current user owns this guild.""" + """[`True`][] when the current user owns this guild.""" my_permissions: permissions_.Permissions = attrs.field(eq=False, hash=False, repr=False) """The guild-level permissions that apply to the current user or bot.""" @@ -328,14 +328,14 @@ class OwnApplicationRoleConnection: metadata: typing.Mapping[str, str] = attrs.field(eq=False, hash=False, repr=False) """Mapping application role connection metadata keys to their value. - .. note:: + !!! note Unfortunately, these can't be deserialized to their proper types as Discord don't provide a way to difference between them. You can deserialize them yourself based on what value you expect from the key: - - `INTEGER_X`: Cast to an `int`. - - `DATETIME_X`: Cast to a `datetime.datetime.fromisoformat` or `ciso8601.parse_rfc3339` for speed. - - `BOOLEAN_X`: Cast to a `bool`. + - `INTEGER_X`: Cast to an [`int`][]. + - `DATETIME_X`: Cast to [`datetime.datetime.fromisoformat`][] or `ciso8601.parse_rfc3339` (for speed). + - `BOOLEAN_X`: Cast to a [`bool`][]. """ @@ -361,7 +361,7 @@ class TeamMember(users.User): permissions: typing.Sequence[str] = attrs.field(repr=False) """This member's permissions within a team. - At the time of writing, this will always be a sequence of one `str`, + At the time of writing, this will always be a sequence of one [`str`][], which will always be `"*"`. This may change in the future, however. """ @@ -461,7 +461,7 @@ class Team(snowflakes.Unique): icon_hash: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) """The CDN hash of this team's icon. - If no icon is provided, this will be `None`. + If no icon is provided, this will be [`None`][]. """ members: typing.Mapping[snowflakes.Snowflake, TeamMember] = attrs.field(eq=False, hash=False, repr=False) @@ -479,7 +479,7 @@ def __str__(self) -> str: @property def icon_url(self) -> typing.Optional[files.URL]: - """Icon URL, or `None` if no icon exists.""" + """Icon URL, or [`None`][] if no icon exists.""" return self.make_icon_url() def make_icon_url(self, *, ext: str = "png", size: int = 4096) -> typing.Optional[files.URL]: @@ -488,16 +488,16 @@ def make_icon_url(self, *, ext: str = "png", size: int = 4096) -> typing.Optiona Parameters ---------- ext : str - The extension to use for this URL, defaults to `png`. + The extension to use for this URL. Supports `png`, `jpeg`, `jpg` and `webp`. size : int - The size to set for the URL, defaults to `4096`. Can be any power - of two between `16` and `4096` inclusive. + The size to set for the URL. + Can be any power of two between 16 and 4096 inclusive. Returns ------- typing.Optional[hikari.files.URL] - The URL, or `None` if no icon exists. + The URL, or [`None`][] if no icon exists. Raises ------ @@ -540,16 +540,16 @@ def make_cover_image_url(self, *, ext: str = "png", size: int = 4096) -> typing. Parameters ---------- ext : str - The extension to use for this URL, defaults to `png`. + The extension to use for this URL. Supports `png`, `jpeg`, `jpg` and `webp`. size : int - The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- typing.Optional[hikari.files.URL] - The URL, or `None` if no cover image exists. + The URL, or [`None`][] if no cover image exists. Raises ------ @@ -588,10 +588,10 @@ class Application(guilds.PartialApplication): """Client application that models may use for procedures.""" is_bot_public: bool = attrs.field(eq=False, hash=False, repr=True) - """`True` if the bot associated with this application is public.""" + """[`True`][] if the bot associated with this application is public.""" is_bot_code_grant_required: bool = attrs.field(eq=False, hash=False, repr=False) - """`True` if this application's bot is requiring code grant for invites.""" + """[`True`][] if this application's bot is requiring code grant for invites.""" owner: users.User = attrs.field(eq=False, hash=False, repr=True) """The application's owner.""" @@ -608,7 +608,7 @@ class Application(guilds.PartialApplication): team: typing.Optional[Team] = attrs.field(eq=False, hash=False, repr=False) """The team this application belongs to. - If the application is not part of a team, this will be `None`. + If the application is not part of a team, this will be [`None`][]. """ cover_image_hash: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) @@ -646,16 +646,16 @@ def make_cover_image_url(self, *, ext: str = "png", size: int = 4096) -> typing. Parameters ---------- ext : str - The extension to use for this URL, defaults to `png`. + The extension to use for this URL. Supports `png`, `jpeg`, `jpg` and `webp`. size : int - The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- typing.Optional[hikari.files.URL] - The URL, or `None` if no cover image exists. + The URL, or [`None`][] if no cover image exists. Raises ------ @@ -674,21 +674,21 @@ def make_cover_image_url(self, *, ext: str = "png", size: int = 4096) -> typing. @attrs_extensions.with_copy @attrs.define(hash=True, kw_only=True, weakref_slot=False) class AuthorizationApplication(guilds.PartialApplication): - """The application model found attached to `AuthorizationInformation`.""" + """The application model found attached to [`hikari.applications.AuthorizationInformation`][].""" public_key: bytes = attrs.field(eq=False, hash=False, repr=False) """The key used for verifying interaction and GameSDK payload signatures.""" is_bot_public: typing.Optional[bool] = attrs.field(eq=False, hash=False, repr=True) - """`True` if the bot associated with this application is public. + """[`True`][] if the bot associated with this application is public. - Will be `None` if this application doesn't have an associated bot. + Will be [`None`][] if this application doesn't have an associated bot. """ is_bot_code_grant_required: typing.Optional[bool] = attrs.field(eq=False, hash=False, repr=False) - """`True` if this application's bot is requiring code grant for invites. + """[`True`][] if this application's bot is requiring code grant for invites. - Will be `None` if this application doesn't have a bot. + Will be [`None`][] if this application doesn't have a bot. """ terms_of_service_url: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) @@ -713,7 +713,11 @@ class AuthorizationInformation: """A sequence of the scopes the current user has authorized the application for.""" user: typing.Optional[users.User] = attrs.field(hash=False, repr=True) - """The user who has authorized this token if they included the `identify` scope.""" + """The user who has authorized this token. + + This will only be included if the token is authorized for the + [`hikari.applications.OAuth2Scope.IDENTIFY`][] scope. + """ @attrs_extensions.with_copy @@ -753,14 +757,14 @@ class OAuth2AuthorizationToken(PartialOAuth2Token): """Object of the webhook that was created. This will only be present if this token was authorized with the - `webhooks.incoming` scope, otherwise this will be `None`. + [`hikari.applications.OAuth2Scope.WEBHOOK_INCOMING`][] scope, otherwise this will be [`None`][]. """ guild: typing.Optional[guilds.RESTGuild] = attrs.field(eq=False, hash=False, repr=True) """Object of the guild the user was added to. This will only be present if this token was authorized with the - `bot` scope, otherwise this will be `None`. + [`hikari.applications.OAuth2Scope.BOT`][] scope, otherwise this will be [`None`][]. """ diff --git a/hikari/audit_logs.py b/hikari/audit_logs.py index 57984e14bd..85031b73bf 100644 --- a/hikari/audit_logs.py +++ b/hikari/audit_logs.py @@ -270,7 +270,7 @@ class AuditLogChangeKey(str, enums.Enum): """Role removed from a member.""" COLOUR = COLOR - """Alias for `COLOR`.""" + """Alias for [`hikari.audit_logs.AuditLogChangeKey.COLOR`][].""" @attrs_extensions.with_copy @@ -395,7 +395,7 @@ async def fetch_channel(self) -> channels.TextableChannel: hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -421,7 +421,8 @@ async def fetch_message(self) -> messages.Message: hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel that the message is in. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] + permission in the channel that the message is in. hikari.errors.NotFoundError If the message is not found. hikari.errors.RateLimitTooLongError @@ -475,7 +476,7 @@ async def fetch_channel(self) -> channels.TextableGuildChannel: hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -519,7 +520,7 @@ async def fetch_channel(self) -> channels.GuildVoiceChannel: hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -553,7 +554,7 @@ class AuditLogEntry(snowflakes.Unique): """The ID of the entity affected by this change, if applicable.""" changes: typing.Sequence[AuditLogChange] = attrs.field(eq=False, hash=False, repr=False) - """A sequence of the changes made to `AuditLogEntry.target_id`.""" + """A sequence of the changes made to [`hikari.audit_logs.AuditLogEntry.target_id`][].""" user_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=True) """The ID of the user who made this change.""" diff --git a/hikari/channels.py b/hikari/channels.py index 7c7519d6a0..cb472b4bc2 100644 --- a/hikari/channels.py +++ b/hikari/channels.py @@ -110,17 +110,17 @@ class ChannelType(int, enums.Enum): """A channel that can be followed and can crosspost.""" GUILD_NEWS_THREAD = 10 - """A temporary sub-channel within a `ChannelType.GUILD_NEWS` channel.""" + """A temporary sub-channel within a [`hikari.channels.ChannelType.GUILD_NEWS`][] channel.""" GUILD_PUBLIC_THREAD = 11 - """A temporary sub-channel within a `ChannelType.GUILD_TEXT` channel.""" + """A temporary sub-channel within a [`hikari.channels.ChannelType.GUILD_TEXT`][] channel.""" GUILD_PRIVATE_THREAD = 12 """A temporary sub-channel with restricted access. - Like `ChannelType.GUILD_PUBLIC_THREAD`, these exist within - `ChannelType.GUILD_TEXT` channels but can only be accessed by members who - are invited to them or have `MANAGE_THREADS` permission. + Like [`hikari.channels.ChannelType.GUILD_PUBLIC_THREAD`][], these exist within + [`hikari.channels.ChannelType.GUILD_TEXT`][] channels but can only be accessed by members who + are invited to them or have [`hikari.permissions.Permissions.MANAGE_THREADS`][] permission. """ GUILD_STAGE = 13 @@ -140,7 +140,7 @@ class ChannelFlag(enums.Flag): PINNED = 1 << 1 """The thread is pinned in a forum channel. - .. note:: + !!! note As of writing, this can only be set for threads belonging to a forum channel. """ @@ -148,7 +148,7 @@ class ChannelFlag(enums.Flag): REQUIRE_TAG = 1 << 4 """Whether a tag is required to be specified when creating a thread in a forum channel - .. note:: + !!! note As of writing, this can only be set for forum channels. """ @@ -192,15 +192,15 @@ async def fetch_channel(self) -> typing.Union[GuildNewsChannel, GuildTextChannel typing.Union[hikari.channels.GuildNewsChannel, hikari.channels.GuildTextChannel] The channel being followed. - While this will usually be `GuildNewsChannel`, if the channel's - news status has been removed then this will be a `GuildTextChannel`. + While this will usually be [`hikari.channels.GuildNewsChannel`][], if the channel's + news status has been removed then this will be a [`hikari.channels.GuildNewsChannel`][]. Raises ------ hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -224,7 +224,7 @@ async def fetch_webhook(self) -> webhooks.ChannelFollowerWebhook: Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_WEBHOOKS` permission in the guild or + If you are missing the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission in the guild or channel this follow is targeting. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). @@ -243,17 +243,17 @@ async def fetch_webhook(self) -> webhooks.ChannelFollowerWebhook: def get_channel(self) -> typing.Union[GuildNewsChannel, GuildTextChannel, None]: """Get the channel being followed from the cache. - .. warning:: - This will always be `None` if you are not + !!! warning + This will always be [`None`][] if you are not in the guild that this channel exists in. Returns ------- typing.Union[hikari.channels.GuildNewsChannel, hikari.channels.GuildTextChannel, None] The object of the guild channel that was found in the cache or - `None`. While this will usually be `GuildNewsChannel` or - `None`, if the channel referenced has since lost it's news - status then this will return a `GuildTextChannel`. + [`None`][]. While this will usually be [`hikari.channels.GuildNewsChannel`][] or + [`None`][], if the channel referenced has since lost it's news + status then this will return a [`hikari.channels.GuildNewsChannel`][]. """ if not isinstance(self.app, traits.CacheAware): return None @@ -286,8 +286,7 @@ class PermissionOverwrite: -------- Creating a permission overwrite. - .. code-block:: python - + ```py overwrite = PermissionOverwrite( id=163979124820541440, type=PermissionOverwriteType.MEMBER, @@ -301,6 +300,7 @@ class PermissionOverwrite: | Permissions.SPEAK ), ) + ``` """ id: snowflakes.Snowflake = attrs.field(converter=snowflakes.Snowflake, repr=True) @@ -352,7 +352,7 @@ class PartialChannel(snowflakes.Unique): def mention(self) -> str: """Return a raw mention string for the channel. - .. note:: + !!! note There are platform specific inconsistencies with mentions of GuildCategories, GroupDMChannels and DMChannels showing the correct name but not being interactable. @@ -370,7 +370,7 @@ def __str__(self) -> str: async def delete(self) -> PartialChannel: """Delete a channel in a guild, or close a DM. - .. note:: + !!! note For Public servers, the set 'Rules' or 'Guidelines' channels and the 'Public Server Updates' channel cannot be deleted. @@ -384,7 +384,7 @@ async def delete(self) -> PartialChannel: hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -412,11 +412,11 @@ def fetch_history( ) -> iterators.LazyIterator[messages_.Message]: """Browse the message history for a given text channel. - .. note:: + !!! note This call is not a coroutine function, it returns a special type of lazy iterator that will perform API calls as you iterate across it, thus any errors documented below will happen then. - See `hikari.iterators` for the full API for this iterator type. + See [`hikari.iterators`][] for the full API for this iterator type. Other Parameters ---------------- @@ -476,7 +476,7 @@ async def fetch_message(self, message: snowflakes.SnowflakeishOr[messages_.Parti hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGE_HISTORY` in the channel. + If you are missing the [`hikari.permissions.Permissions.READ_MESSAGE_HISTORY`][] in the channel. hikari.errors.NotFoundError If the channel is not found or the message is not found in the given text channel. @@ -521,15 +521,15 @@ async def send( ---------- content : hikari.undefined.UndefinedOr[typing.Any] If provided, the message contents. If - `hikari.undefined.UNDEFINED`, then nothing will be sent + [`hikari.undefined.UNDEFINED`][], then nothing will be sent in the content. Any other value here will be cast to a - `str`. + [`str`][]. - If this is a `hikari.embeds.Embed` and no `embed` nor `embeds` kwarg + 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 + 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. @@ -542,26 +542,26 @@ async def send( Attachments can be passed as many different things, to aid in convenience. - - If a `pathlib.PurePath` or `str` to a valid URL, the + - 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. + [`hikari.files.WebResource`][] such as + [`hikari.files.URL`][], + [`hikari.messages.Attachment`][], + [`hikari.emojis.Emoji`][], + [`hikari.embeds.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` + - 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 + - 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 + 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]] @@ -592,7 +592,6 @@ async def send( reply_must_exist : hikari.undefined.UndefinedOr[bool] If provided, whether to error if the message being replied to does not exist instead of sending as a normal (non-reply) message. - Defaults to `True`. This will not do anything if not being used with `reply`. mentions_everyone : hikari.undefined.UndefinedOr[bool] @@ -604,25 +603,25 @@ async def send( 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 mentions will be parsed. - If provided, and `False`, no mentions will be parsed. + If provided, and [`True`][], all mentions will be parsed. + If provided, and [`False`][], no mentions will be parsed. Alternatively this may be a collection of - `hikari.snowflakes.Snowflake`, or - `hikari.users.PartialUser` derivatives to enforce mentioning + [`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 mentions will be parsed. - If provided, and `False`, no mentions will be parsed. + If provided, and [`True`][], all mentions will be parsed. + If provided, and [`False`][], no mentions will be parsed. Alternatively this may be a collection of - `hikari.snowflakes.Snowflake`, or - `hikari.guilds.PartialRole` derivatives to enforce mentioning + [`hikari.snowflakes.Snowflake`][], or + [`hikari.guilds.PartialRole`][] derivatives to enforce mentioning specific roles. flags : hikari.undefined.UndefinedOr[hikari.messages.MessageFlag] If provided, optional flags to set on the message. If - `hikari.undefined.UNDEFINED`, then nothing is changed. + [`hikari.undefined.UNDEFINED`][], then nothing is changed. Note that some flags may not be able to be set. Currently the only - flags that can be set are `NONE` and `SUPPRESS_EMBEDS`. + flags that can be set are [`hikari.messages.MessageFlag.NONE`][] and [`hikari.messages.MessageFlag.SUPPRESS_EMBEDS`][]. Returns ------- @@ -680,14 +679,14 @@ def trigger_typing(self) -> special_endpoints.TypingIndicator: once, or used as an async context manager to keep typing until the block completes. - .. code-block:: python - + ```py await channel.trigger_typing() # type for 10s async with channel.trigger_typing(): await asyncio.sleep(35) # keep typing until this finishes + ``` - .. note:: + !!! note Sending a message to this channel will stop the typing indicator. If using an `async with`, it will start up again after a few seconds. This is a limitation of Discord's API. @@ -712,7 +711,8 @@ async def fetch_pins(self) -> typing.Sequence[messages_.Message]: hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` in the channel. + If you are missing the [hikari.permissions.Permissions.VIEW_CHANNEL] + permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -737,7 +737,7 @@ async def pin_message(self, message: snowflakes.SnowflakeishOr[messages_.Partial hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_MESSAGES` in the channel. + If you are missing the [`hikari.permissions.Permissions.MANAGE_MESSAGES`][] in the channel. hikari.errors.NotFoundError If the channel is not found, or if the message does not exist in the given channel. @@ -763,7 +763,7 @@ async def unpin_message(self, message: snowflakes.SnowflakeishOr[messages_.Parti hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_MESSAGES` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_MESSAGES`][] permission. hikari.errors.NotFoundError If the channel is not found or the message is not a pinned message in the given channel. @@ -787,7 +787,7 @@ async def delete_messages( ) -> None: """Bulk-delete messages from the channel. - .. note:: + !!! note This API endpoint will only be able to delete 100 messages at a time. For anything more than this, multiple requests will be executed one-after-the-other, since the rate limits for this @@ -799,12 +799,12 @@ async def delete_messages( of this is that the `delete_message` endpoint is ratelimited by a different bucket with different usage rates. - .. warning:: + !!! warning This endpoint is not atomic. If an error occurs midway through a bulk delete, you will **not** be able to revert any changes made up to this point. - .. warning:: + !!! warning Specifying any messages more than 14 days old will cause the call to fail, potentially with partial completion. @@ -824,7 +824,7 @@ async def delete_messages( hikari.errors.BulkDeleteError An error containing the messages successfully deleted, and the messages that were not removed. The - `BaseException.__cause__` of the exception will be the + [`BaseException.__cause__`][] of the exception will be the original error that terminated this process. """ return await self.app.rest.delete_messages(self.id, messages, *other_messages) @@ -837,7 +837,7 @@ class PrivateChannel(PartialChannel): last_message_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) """The ID of the last message sent in this channel. - .. warning:: + !!! warning This might point to an invalid or deleted message. Do not assume that this will always be valid. """ @@ -863,10 +863,10 @@ def __str__(self) -> str: class GroupDMChannel(PrivateChannel): """Represents a group direct message channel. - .. note:: - This doesn't have the methods found on `TextableChannel` as bots cannot - interact with a group DM that they own by sending or seeing messages in - it. + !!! note + This doesn't have the methods found on [`hikari.channels.TextableChannel`][] + as bots cannot interact with a group DM that they own by sending or + seeing messages in it. """ owner_id: snowflakes.Snowflake = attrs.field(eq=False, hash=False, repr=True) @@ -884,7 +884,7 @@ class GroupDMChannel(PrivateChannel): application_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) """The ID of the application that created the group DM. - If the group DM was not created by a bot, this will be `None`. + If the group DM was not created by a bot, this will be [`None`][]. """ def __str__(self) -> str: @@ -904,16 +904,16 @@ def make_icon_url(self, *, ext: str = "png", size: int = 4096) -> typing.Optiona Parameters ---------- ext : str - The extension to use for this URL, defaults to `png`. + The extension to use for this URL. Supports `png`, `jpeg`, `jpg` and `webp`. size : int - The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- typing.Optional[hikari.files.URL] - The URL, or `None` if no icon is present. + The URL, or [`None`][] if no icon is present. Raises ------ @@ -940,15 +940,15 @@ class GuildChannel(PartialChannel): For thread channels this will refer to the parent textable guild channel. For other guild channel types this will refer to the parent category and - if no parent category is set for the channel, this will be `None`. - For guild categories this will always be `None`. + if no parent category is set for the channel, this will be [`None`][]. + For guild categories this will always be [`None`][]. """ @property def shard_id(self) -> typing.Optional[int]: """Return the shard ID for the shard. - This may be `None` if the shard count is not known. + This may be [`None`][] if the shard count is not known. """ if isinstance(self.app, traits.ShardAware): return snowflakes.calculate_shard_id(self.app, self.guild_id) @@ -961,7 +961,7 @@ def get_guild(self) -> typing.Optional[guilds.GatewayGuild]: Returns ------- typing.Optional[hikari.guilds.Guild] - The linked guild object or `None` if it's not cached. + The linked guild object or [`None`][] if it's not cached. """ if not isinstance(self.app, traits.CacheAware): return None @@ -1039,7 +1039,7 @@ async def edit( If provided, the new rate limit per user in the channel. region : hikari.undefined.UndefinedOr[typing.Union[hikari.voices.VoiceRegion, str]] If provided, the voice region to set for this channel. Passing - `None` here will set it to "auto" mode where the used + [`None`][] here will set it to "auto" mode where the used region will be decided based on the first person who connects to it when it's empty. permission_overwrites : hikari.undefined.UndefinedOr[typing.Sequence[hikari.channels.PermissionOverwrite]] @@ -1069,7 +1069,7 @@ async def edit( If provided, the new locked state for the thread. This only applies to threads. - If it's locked then only people with `MANAGE_THREADS` can unarchive it. + If it's locked then only people with [`hikari.permissions.Permissions.MANAGE_THREADS`][] can unarchive it. invitable : hikari.undefined.UndefinedOr[bool] If provided, the new setting for whether non-moderators can invite new members to a private thread. This only applies to threads. @@ -1129,7 +1129,7 @@ async def edit( class PermissibleGuildChannel(GuildChannel): """Base class for all guild channels which have permission overwrites. - .. note:: + !!! note This doesn't apply to thread channels as they implicitly inherit permissions from their parent channel. """ @@ -1193,7 +1193,8 @@ async def edit_overwrite( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_PERMISSIONS` permission in the channel. + If you are missing the [`MANAGE_PERMISSIONS`][hikari.permissions.Permissions.MANAGE_ROLES] + permission in the channel. hikari.errors.NotFoundError If the channel is not found or the target is not found if it is a role. @@ -1228,7 +1229,8 @@ async def remove_overwrite( hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_PERMISSIONS` permission in the channel. + If you are missing the [`MANAGE_PERMISSIONS`][hikari.permissions.Permissions.MANAGE_ROLES] + permission in the channel. hikari.errors.NotFoundError If the channel is not found or the target is not found. hikari.errors.RateLimitTooLongError @@ -1258,7 +1260,7 @@ class GuildCategory(PermissibleGuildChannel): parent_id: None = attrs.field(eq=False, hash=False, repr=True) """The ID of the parent channel the channel belongs to. - This is always `None` for categories. + This is always [`None`][] for categories. """ @@ -1272,7 +1274,7 @@ class GuildTextChannel(PermissibleGuildChannel, TextableGuildChannel): last_message_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) """The ID of the last message sent in this channel. - .. warning:: + !!! warning This might point to an invalid or deleted message. Do not assume that this will always be valid. """ @@ -1282,17 +1284,18 @@ class GuildTextChannel(PermissibleGuildChannel, TextableGuildChannel): If there is no rate limit, this will be 0 seconds. - .. note:: - Any user that has permissions allowing `MANAGE_MESSAGES`, - `MANAGE_CHANNEL`, `ADMINISTRATOR` will not be limited. Likewise, bots - will not be affected by this rate limit. + !!! note + Any user that has permissions allowing [`hikari.permissions.Permissions.MANAGE_MESSAGES`][], + [`hikari.permissions.Permissions.MANAGE_CHANNELS`][], + [`hikari.permissions.Permissions.ADMINISTRATOR`][] will not be limited. + Likewise, bots will not be affected by this rate limit. """ last_pin_timestamp: typing.Optional[datetime.datetime] = attrs.field(eq=False, hash=False, repr=False) """The timestamp of the last-pinned message. - .. note:: - This may be `None` in several cases; Discord does not document what + !!! note + This may be [`None`][] in several cases; Discord does not document what these cases are. Trust no one! """ @@ -1313,7 +1316,7 @@ class GuildNewsChannel(PermissibleGuildChannel, TextableGuildChannel): last_message_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) """The ID of the last message sent in this channel. - .. warning:: + !!! warning This might point to an invalid or deleted message. Do not assume that this will always be valid. """ @@ -1321,8 +1324,8 @@ class GuildNewsChannel(PermissibleGuildChannel, TextableGuildChannel): last_pin_timestamp: typing.Optional[datetime.datetime] = attrs.field(eq=False, hash=False, repr=False) """The timestamp of the last-pinned message. - .. note:: - This may be `None` in several cases; Discord does not document what + !!! note + This may be [`None`][] in several cases; Discord does not document what these cases are. Trust no one! """ @@ -1343,7 +1346,7 @@ class GuildVoiceChannel(PermissibleGuildChannel, TextableGuildChannel): region: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) """ID of the voice region for this voice channel. - If set to `None` then this is set to "auto" mode where the used + If set to [`None`][] then this is set to "auto" mode where the used region will be decided based on the first person who connects to it when it's empty. """ @@ -1360,7 +1363,7 @@ class GuildVoiceChannel(PermissibleGuildChannel, TextableGuildChannel): last_message_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) """The ID of the last message sent in this channel. - .. warning:: + !!! warning This might point to an invalid or deleted message. Do not assume that this will always be valid. """ @@ -1376,7 +1379,7 @@ class GuildStageChannel(PermissibleGuildChannel, TextableGuildChannel): region: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) """ID of the voice region for this stage channel. - If set to `None` then this is set to "auto" mode where the used + If set to [`None`][] then this is set to "auto" mode where the used region will be decided based on the first person who connects to it when it's empty. """ @@ -1390,7 +1393,7 @@ class GuildStageChannel(PermissibleGuildChannel, TextableGuildChannel): last_message_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) """The ID of the last message sent in this channel. - .. warning:: + !!! warning This might point to an invalid or deleted message. Do not assume that this will always be valid. """ @@ -1439,7 +1442,8 @@ class ForumTag(snowflakes.Unique): moderated: bool = attrs.field(eq=False, hash=False, repr=False, default=False) """The whether this flag can only be applied by moderators. - Moderators are those with `MANAGE_CHANNEL` or `ADMINISTRATOR` permissions. + Moderators are those with [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] + or [`hikari.permissions.Permissions.ADMINISTRATOR`][] permissions. """ _emoji: typing.Union[str, int, emojis.Emoji, None] = attrs.field(alias="emoji", default=None) @@ -1474,7 +1478,7 @@ class GuildForumChannel(PermissibleGuildChannel): last_thread_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) """The ID of the last thread created in this channel. - .. warning:: + !!! warning This might point to an invalid or deleted message. Do not assume that this will always be valid. """ @@ -1484,10 +1488,11 @@ class GuildForumChannel(PermissibleGuildChannel): If there is no rate limit, this will be 0 seconds. - .. note:: - Any user that has permissions allowing `MANAGE_MESSAGES`, - `MANAGE_CHANNEL`, `ADMINISTRATOR` will not be limited. Likewise, bots - will not be affected by this rate limit. + !!! note + Any user that has permissions allowing [`hikari.permissions.Permissions.MANAGE_MESSAGES`][], + [`hikari.permissions.Permissions.MANAGE_CHANNELS`][], + [`hikari.permissions.Permissions.ADMINISTRATOR`][] will not be limited. + Likewise, bots will not be affected by this rate limit. """ default_thread_rate_limit_per_user: datetime.timedelta = attrs.field(eq=False, hash=False, repr=False) @@ -1495,10 +1500,11 @@ class GuildForumChannel(PermissibleGuildChannel): If there is no rate limit, this will be 0 seconds. - .. note:: - Any user that has permissions allowing `MANAGE_MESSAGES`, - `MANAGE_CHANNEL`, `ADMINISTRATOR` will not be limited. Likewise, bots - will not be affected by this rate limit. + !!! note + Any user that has permissions allowing [`hikari.permissions.Permissions.MANAGE_MESSAGES`][], + [`hikari.permissions.Permissions.MANAGE_CHANNELS`][], + [`hikari.permissions.Permissions.ADMINISTRATOR`][] will not be limited. + Likewise, bots will not be affected by this rate limit. """ default_auto_archive_duration: datetime.timedelta = attrs.field(eq=False, hash=False, repr=False) @@ -1510,8 +1516,8 @@ class GuildForumChannel(PermissibleGuildChannel): flags: ChannelFlag = attrs.field(eq=False, hash=False, repr=False) """The channel flags for this channel. - .. note:: - As of writing, the only flag that can be set is `ChannelFlag.REQUIRE_TAG`. + !!! note + As of writing, the only flag that can be set is [`hikari.channels.ChannelFlag.REQUIRE_TAG`][]. """ available_tags: typing.Sequence[ForumTag] = attrs.field(eq=False, hash=False, repr=False) @@ -1532,7 +1538,7 @@ class GuildForumChannel(PermissibleGuildChannel): """Name of the default reaction emoji. Either the string name of the custom emoji, the object - of the `hikari.emojis.UnicodeEmoji` or `None` when the relevant + of the [`hikari.emojis.UnicodeEmoji`][] or [`None`][] when the relevant custom emoji's data is not available (e.g. the emoji has been deleted). """ @@ -1542,20 +1548,20 @@ class GuildForumChannel(PermissibleGuildChannel): The following types are in this: -* `GuildTextChannel` -* `GuildNewsChannel` +* [`hikari.channels.GuildTextChannel`][] +* [`hikari.channels.GuildNewsChannel`][] """ WebhookChannelTypes: typing.Tuple[typing.Type[GuildTextChannel], typing.Type[GuildNewsChannel]] = ( GuildTextChannel, GuildNewsChannel, ) -"""Tuple of the channel types which are valid for `WebhookChannelT`. +"""Tuple of the channel types which are valid for [`hikari.channels.WebhookChannelT`][]. This includes: -* `GuildTextChannel` -* `GuildNewsChannel` +* [`hikari.channels.GuildTextChannel`][] +* [`hikari.channels.GuildNewsChannel`][] """ @@ -1569,8 +1575,8 @@ class ThreadMember: user_id: snowflakes.Snowflake = attrs.field(eq=True, repr=True) """The member's user ID. - .. note:: - This will only ever be `None` on thread members attached to + !!! note + This will only ever be [`None`][] on thread members attached to guild create events, where this is the current bot's user. """ @@ -1580,7 +1586,7 @@ class ThreadMember: flags: int = attrs.field(eq=True, repr=True) """Bitfield flag of the user's settings for the thread. - .. note:: + !!! note As of writing, the values of this field's are undocumented. """ @@ -1592,7 +1598,7 @@ class GuildThreadChannel(TextableGuildChannel): last_message_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) """The ID of the last message sent in this channel. - .. warning:: + !!! warning This might point to an invalid or deleted message. Do not assume that this will always be valid. """ @@ -1600,8 +1606,8 @@ class GuildThreadChannel(TextableGuildChannel): last_pin_timestamp: typing.Optional[datetime.datetime] = attrs.field(eq=False, hash=False, repr=False) """The timestamp of the last-pinned message. - .. note:: - This may be `None` in several cases; Discord does not document what + !!! note + This may be [`None`][] in several cases; Discord does not document what these cases are. Trust no one! """ @@ -1610,23 +1616,24 @@ class GuildThreadChannel(TextableGuildChannel): If there is no rate limit, this will be 0 seconds. - .. note:: - Any user that has permissions allowing `MANAGE_MESSAGES`, - `MANAGE_CHANNEL`, `ADMINISTRATOR` will not be limited. Likewise, bots - will not be affected by this rate limit. + !!! note + Any user that has permissions allowing [`hikari.permissions.Permissions.MANAGE_MESSAGES`][], + [`hikari.permissions.Permissions.MANAGE_CHANNELS`][], + [`hikari.permissions.Permissions.ADMINISTRATOR`][] will not be limited. + Likewise, bots will not be affected by this rate limit. """ approximate_message_count: int = attrs.field(eq=False, hash=False, repr=True) """Approximate number of messages in the thread channel. - .. warning:: + !!! warning This stops counting at 50 for threads created before 2022/06/01. """ approximate_member_count: int = attrs.field(eq=False, hash=False, repr=True) """Approximate count of members in the thread channel. - .. warning:: + !!! warning This stop counting at 50. """ @@ -1642,7 +1649,7 @@ class GuildThreadChannel(TextableGuildChannel): archive_timestamp: datetime.datetime = attrs.field(eq=False, hash=False, repr=True) """When the thread's archived state was last changed. - .. note:: + !!! note If the thread has never been archived then this will be the thread's creation date and this will be changed when a thread is unarchived. """ @@ -1650,14 +1657,14 @@ class GuildThreadChannel(TextableGuildChannel): is_locked: bool = attrs.field(eq=False, hash=False, repr=True) """Whether the thread is locked. - When a thread is locked, only users with `MANAGE_THREADS` permission + When a thread is locked, only users with [`hikari.permissions.Permissions.MANAGE_THREADS`][] permission can un-archive it. """ member: typing.Optional[ThreadMember] = attrs.field(eq=False, hash=False, repr=True) """Thread member object for the current user, if they are in the thread. - .. note:: + !!! note This is only returned by some endpoints and on private thread access events. """ @@ -1671,7 +1678,7 @@ class GuildThreadChannel(TextableGuildChannel): thread_created_at: typing.Optional[datetime.datetime] = attrs.field(eq=False, hash=False, repr=True) """When the thread was created. - Will be `None` for threads created before 2020-01-09. + Will be [`None`][] for threads created before 2020-01-09. """ @@ -1696,8 +1703,8 @@ class GuildPublicThread(GuildThreadChannel): This will only apply to threads created inside a forum channel. - .. note:: - As of writing, the only flag that can be set is `ChannelFlag.PINNED`. + !!! note + As of writing, the only flag that can be set is [`hikari.channels.ChannelFlag.PINNED`][]. """ diff --git a/hikari/colors.py b/hikari/colors.py index 2d53ebeed2..68facb3dac 100644 --- a/hikari/colors.py +++ b/hikari/colors.py @@ -52,7 +52,7 @@ def _to_rgb_int(value: str, name: str) -> int: def _to_rgb_float(value: str, name: str) -> float: - # Floats are easier to handle, as they don't overflow, they just become `inf`. + # Floats are easier to handle, as they don't overflow, they just become [`inf`][]. if value.count(".") != 1: raise ValueError(f'Expected exactly 1 decimal point "." in {name} channel') @@ -66,7 +66,7 @@ class Color(int): This value is immutable. - This is a specialization of `int` which provides alternative overrides for + This is a specialization of [`int`][] which provides alternative overrides for common methods and color system conversions. This currently supports: @@ -82,8 +82,7 @@ class Color(int): -------- Examples of conversions to given formats include: - .. code-block:: python - + ```py >>> c = Color(0xFF051A) Color(r=0xff, g=0x5, b=0x1a) @@ -104,13 +103,13 @@ class Color(int): >>> c.rgb_float (1.0, 0.0196078431372549, 0.10196078431372549) + ``` Alternatively, if you have an arbitrary input in one of the above formats - that you wish to become a color, you can use `Color.of` on the class itself - to automatically attempt to resolve the color: - - .. code-block:: python + that you wish to become a color, you can use [`hikari.colors.Color.of`][] on + the class itself to automatically attempt to resolve the color: + ```py >>> Color.of(0xFF051A) Color(r=0xff, g=0x5, b=0x1a) @@ -137,11 +136,11 @@ class Color(int): >>> c = Color.of([1.0, 0.0196078431372549, 0.10196078431372549]) Color(r=0xff, g=0x5, b=0x1a) + ``` Examples of initialization of Color objects from given formats include: - .. code-block:: python - + ```py >>> c = Color(16712986) Color(r=0xff, g=0x5, b=0x1a) @@ -156,6 +155,7 @@ class Color(int): >>> c = Color.from_rgb_float(1.0, 0.0196078431372549, 0.10196078431372549) Color(r=0xff, g=0x5, b=0x1a) + ``` """ __slots__: typing.Sequence[str] = () @@ -163,7 +163,7 @@ class Color(int): def __init__(self, raw_rgb: typing.SupportsInt) -> None: if not (0 <= int(raw_rgb) <= 0xFFFFFF): raise ValueError(f"raw_rgb must be in the exclusive range of 0 and {0xFF_FF_FF}") - # The __new__ for `int` initializes the value for us, this super-call does nothing other + # The __new__ for [`int`][] initializes the value for us, this super-call does nothing other # than keeping the linter happy. super().__init__() @@ -183,7 +183,7 @@ def rgb(self) -> typing.Tuple[int, int, int]: Examples -------- - `(123, 234, 47)` + [(123, 234, 47)][] """ return (self >> 16) & 0xFF, (self >> 8) & 0xFF, self & 0xFF @@ -195,7 +195,7 @@ def rgb_float(self) -> typing.Tuple[float, float, float]: Examples -------- - `(0.1, 0.2, 0.76)` + [(0.1, 0.2, 0.76)][] """ r, g, b = self.rgb return r / 0xFF, g / 0xFF, b / 0xFF @@ -230,7 +230,7 @@ def is_web_safe(self) -> bool: @classmethod def from_rgb(cls, red: int, green: int, blue: int, /) -> Color: - """Convert the given RGB to a `Color` object. + """Convert the given RGB to a [`hikari.colors.Color`][] object. Each channel must be within the range [0, 255] (0x0, 0xFF). @@ -263,7 +263,7 @@ def from_rgb(cls, red: int, green: int, blue: int, /) -> Color: @classmethod def from_rgb_float(cls, red: float, green: float, blue: float, /) -> Color: - """Convert the given RGB to a `Color` object. + """Convert the given RGB to a [`hikari.colors.Color`][] object. The color-space represented values have to be within the range [0, 1]. @@ -297,7 +297,7 @@ def from_rgb_float(cls, red: float, green: float, blue: float, /) -> Color: @classmethod def from_hex_code(cls, hex_code: str, /) -> Color: - """Convert the given hexadecimal color code to a `Color`. + """Convert the given hexadecimal color code to a [`hikari.colors.Color`][]. The inputs may be of the following format (case insensitive): `1a2`, `#1a2`, `0x1a2` (for web-safe colors), or @@ -339,7 +339,7 @@ def from_hex_code(cls, hex_code: str, /) -> Color: @classmethod def from_int(cls, integer: typing.SupportsInt, /) -> Color: - """Convert the given `typing.SupportsInt` to a `Color`. + """Convert the given [`typing.SupportsInt`][] to a [`hikari.colors.Color`][]. Parameters ---------- @@ -355,11 +355,11 @@ def from_int(cls, integer: typing.SupportsInt, /) -> Color: @classmethod def from_tuple_string(cls, tuple_str: str, /) -> Color: - """Convert a string in a tuple-like format to a `Color`. + """Convert a string in a tuple-like format to a [`hikari.colors.Color`][]. - This allows formats that are optionally enclosed by `()`, `{}`, or - `[]`, and contain three floats or ints, either space separated or - comma separated. + This allows formats that are optionally enclosed by `()`, + `{}`, `[]` or `<>`, and contain three floats or ints, + either space separated or comma separated. If comma separated, trailing and leading whitespace around each member is truncated. @@ -369,8 +369,7 @@ def from_tuple_string(cls, tuple_str: str, /) -> Color: Examples -------- - .. code-block:: python - + ```py # Floats "1.0 1.0 1.0" "(1.0 1.0 1.0)" @@ -390,6 +389,7 @@ def from_tuple_string(cls, tuple_str: str, /) -> Color: "(252, 252, 252)" "[252, 252, 252]" "{252, 252, 252}" + ``` Parameters ---------- @@ -425,7 +425,7 @@ def from_tuple_string(cls, tuple_str: str, /) -> Color: @classmethod def of(cls, value: Colorish, /) -> Color: - """Convert the value to a `Color`. + """Convert the value to a [`hikari.colors.Color`][]. This attempts to determine the correct data format based on the information provided. @@ -437,8 +437,7 @@ def of(cls, value: Colorish, /) -> Color: Examples -------- - .. code-block:: python - + ```py >>> Color.of(0xFF051A) Color(r=0xff, g=0x5, b=0x1a) @@ -474,6 +473,7 @@ def of(cls, value: Colorish, /) -> Color: Color(r=0x5, g=0x16, b=0x21) >>> c = Color.of("{5, 22, 33}") Color(r=0x5, g=0x16, b=0x21) + ``` Returns ------- @@ -543,14 +543,14 @@ def to_bytes( This may be: -1. `hikari.colors.Color` -2. `hikari.colours.Colour` (an alias for `hikari.colors.Color`). -3. A value that can be cast to an `int` (RGB hex-code). -4. a 3-`tuple` of `int` (RGB integers in range 0 through 255). -5. a 3-`tuple` of `float` (RGB floats in range 0 through 1). -6. a list of `int`. -7. a list of `float`. -8. a `str` hex colour code. +1. [`hikari.colors.Color`][] +2. [`hikari.colours.Colour`][] (an alias for [`hikari.colors.Color`][]). +3. A value that can be cast to an [`int`][] (RGB hex-code). +4. a 3-[`tuple`][] of [`int`][] (RGB integers in range 0 through 255). +5. a 3-[`tuple`][] of [`float`][] (RGB floats in range 0 through 1). +6. a list of [`int`][]. +7. a list of [`float`][]. +8. a [`str`][] hex colour code. A hex colour code is expected to be in one of the following formats. Each of the following examples means the same thing semantically. diff --git a/hikari/colours.py b/hikari/colours.py index a456f99068..51d5daa69f 100644 --- a/hikari/colours.py +++ b/hikari/colours.py @@ -20,7 +20,7 @@ # 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. -"""Alias for the `hikari.colors` module.""" +"""Alias for the [`hikari.colors`][] module.""" from __future__ import annotations @@ -31,7 +31,7 @@ from hikari import colors Colour = colors.Color -"""An alias for `hikari.colors.Color`.""" +"""An alias for [`hikari.colors.Color`][].""" Colourish = colors.Colorish -"""An alias for `hikari.colors.Colorish`.""" +"""An alias for [`hikari.colors.Colorish`][].""" diff --git a/hikari/commands.py b/hikari/commands.py index 815c993fac..691a675134 100644 --- a/hikari/commands.py +++ b/hikari/commands.py @@ -138,7 +138,7 @@ class CommandOption: name: str = attrs.field(repr=True) r"""The command option's name. - .. note:: + !!! note This will match the regex `^[-_\p{L}\p{N}\p{sc=Deva}\p{sc=Thai}]{1,32}$` in Unicode mode and will be lowercase. """ @@ -146,7 +146,7 @@ class CommandOption: description: str = attrs.field(repr=False) """The command option's description. - .. note:: + !!! note This will be inclusively between 1-100 characters in length. """ @@ -156,7 +156,7 @@ class CommandOption: choices: typing.Optional[typing.Sequence[CommandChoice]] = attrs.field(default=None, repr=False) """A sequence of up to (and including) 25 choices for this command. - This will be `None` if the input values for this option aren't + This will be [`None`][] if the input values for this option aren't limited to specific values or if it's a subcommand or subcommand-group type option. """ @@ -169,7 +169,7 @@ class CommandOption: ) """The channel types that this option will accept. - If `None`, then all channel types will be accepted. + If [`None`][], then all channel types will be accepted. """ autocomplete: bool = attrs.field(default=False, repr=False) @@ -178,15 +178,15 @@ class CommandOption: min_value: typing.Union[int, float, None] = attrs.field(default=None, repr=False) """The minimum value permitted (inclusive). - This will be `int` if the type of the option is `hikari.commands.OptionType.INTEGER` - and `float` if the type is `hikari.commands.OptionType.FLOAT`. + This will be [`int`][] if the type of the option is [`hikari.commands.OptionType.INTEGER`][] + and [`float`][] if the type is [`hikari.commands.OptionType.FLOAT`][]. """ max_value: typing.Union[int, float, None] = attrs.field(default=None, repr=False) """The maximum value permitted (inclusive). - This will be `int` if the type of the option is `hikari.commands.OptionType.INTEGER` - and `float` if the type is `hikari.commands.OptionType.FLOAT`. + This will be [`int`][] if the type of the option is [`hikari.commands.OptionType.INTEGER`][] + and [`float`][] if the type is [`hikari.commands.OptionType.FLOAT`][]. """ name_localizations: typing.Mapping[typing.Union[locales.Locale, str], str] = attrs.field( @@ -202,13 +202,15 @@ class CommandOption: min_length: typing.Optional[int] = attrs.field(default=None, repr=False) """The minimum length permitted (inclusive). - This is only valid for `hikari.commands.OptionType.STRING`, otherwise it will be `None`. + This is only valid for [`hikari.commands.OptionType.STRING`][], + otherwise it will be [`None`][]. """ max_length: typing.Optional[int] = attrs.field(default=None, repr=False) """The maximum length permitted (inclusive). - This is only valid for `hikari.commands.OptionType.STRING`, otherwise it will be `None`. + This is only valid for [`hikari.commands.OptionType.STRING`][], + otherwise it will be [`None`][]. """ @@ -232,7 +234,7 @@ class PartialCommand(snowflakes.Unique): name: str = attrs.field(eq=False, hash=False, repr=True) r"""The command's name. - .. note:: + !!! note This will match the regex `^[-_\p{L}\p{N}\p{sc=Deva}\p{sc=Thai}]{1,32}$` in Unicode mode and will be lowercase. """ @@ -252,7 +254,7 @@ class PartialCommand(snowflakes.Unique): guild_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) """ID of the guild this command is in. - This will be `None` if this is a global command. + This will be [`None`][] if this is a global command. """ version: snowflakes.Snowflake = attrs.field(eq=False, hash=False, repr=True) @@ -302,14 +304,14 @@ async def edit( Other Parameters ---------------- name : hikari.undefined.UndefinedOr[str] - The name to set for the command. Leave as `hikari.undefined.UNDEFINED` + The name to set for the command. Leave as [`hikari.undefined.UNDEFINED`][] to not change. description : hikari.undefined.UndefinedOr[str] - The description to set for the command. Leave as `hikari.undefined.UNDEFINED` + The description to set for the command. Leave as [`hikari.undefined.UNDEFINED`][] to not change. options : hikari.undefined.UndefinedOr[typing.Sequence[CommandOption]] A sequence of up to 10 options to set for this command. Leave this as - `hikari.undefined.UNDEFINED` to not change. + [`hikari.undefined.UNDEFINED`][] to not change. Returns ------- @@ -401,7 +403,7 @@ async def set_guild_permissions( ) -> GuildCommandPermissions: """Set permissions for this command in a specific guild. - .. note:: + !!! note This overwrites any previously set permissions. Parameters @@ -445,7 +447,7 @@ class SlashCommand(PartialCommand): None if this command is not a slash command. - .. note:: + !!! note This will be inclusively between 1-100 characters in length. """ diff --git a/hikari/components.py b/hikari/components.py index 37ca57236a..24baa2f6c0 100644 --- a/hikari/components.py +++ b/hikari/components.py @@ -60,71 +60,71 @@ class ComponentType(int, enums.Enum): ACTION_ROW = 1 """A non-interactive container component for other types of components. - .. note:: + !!! note As this is a container component it can never be contained within another component and therefore will always be top-level. - .. note:: + !!! note As of writing this can only contain one component type. """ BUTTON = 2 """A button component. - .. note:: + !!! note This cannot be top-level and must be within a container component such - as `ComponentType.ACTION_ROW`. + as [`hikari.components.ComponentType.ACTION_ROW`][]. """ TEXT_SELECT_MENU = 3 """A text select component. - .. note:: + !!! note This cannot be top-level and must be within a container component such - as `ComponentType.ACTION_ROW`. + as [`hikari.components.ComponentType.ACTION_ROW`][]. """ TEXT_INPUT = 4 """A text input component. - .. note:: + !!! note This component may only be used inside a modal container. - .. note:: + !!! note This cannot be top-level and must be within a container component such - as `ComponentType.ACTION_ROW`. + as [`hikari.components.ComponentType.ACTION_ROW`][]. """ USER_SELECT_MENU = 5 """A user select component. - .. note:: + !!! note This cannot be top-level and must be within a container component such - as `ComponentType.ACTION_ROW`. + as [`hikari.components.ComponentType.ACTION_ROW`][]. """ ROLE_SELECT_MENU = 6 """A role select component. - .. note:: + !!! note This cannot be top-level and must be within a container component such - as `ComponentType.ACTION_ROW`. + as [`hikari.components.ComponentType.ACTION_ROW`][]. """ MENTIONABLE_SELECT_MENU = 7 """A mentionable (users and roles) select component. - .. note:: + !!! note This cannot be top-level and must be within a container component such - as `ComponentType.ACTION_ROW`. + as [`hikari.components.ComponentType.ACTION_ROW`][]. """ CHANNEL_SELECT_MENU = 8 """A channel select component. - .. note:: + !!! note This cannot be top-level and must be within a container component such - as `ComponentType.ACTION_ROW`. + as [`hikari.components.ComponentType.ACTION_ROW`][]. """ @@ -151,7 +151,7 @@ class ButtonStyle(int, enums.Enum): LINK = 5 """A grey button which navigates to a URL. - .. warning:: + !!! warning Unlike the other button styles, clicking this one will not trigger an interaction and custom_id shouldn't be included for this style. """ @@ -220,17 +220,17 @@ class ButtonComponent(PartialComponent): custom_id: typing.Optional[str] = attrs.field(hash=True) """Developer defined identifier for this button (will be <= 100 characters). - .. note:: + !!! note This is required for the following button styles: - * `ButtonStyle.PRIMARY` - * `ButtonStyle.SECONDARY` - * `ButtonStyle.SUCCESS` - * `ButtonStyle.DANGER` + * [`hikari.components.ButtonStyle.PRIMARY`][] + * [`hikari.components.ButtonStyle.SECONDARY`][] + * [`hikari.components.ButtonStyle.SUCCESS`][] + * [`hikari.components.ButtonStyle.DANGER`][] """ url: typing.Optional[str] = attrs.field(eq=False) - """Url for `ButtonStyle.LINK` style buttons.""" + """Url for [`hikari.components.ButtonStyle.LINK`][] style buttons.""" is_disabled: bool = attrs.field(eq=False) """Whether the button is disabled.""" @@ -238,7 +238,7 @@ class ButtonComponent(PartialComponent): @attrs.define(kw_only=True, weakref_slot=False) class SelectMenuOption: - """Represents an option for a `SelectMenuComponent`.""" + """Represents an option for a [`hikari.components.SelectMenuComponent`][].""" label: str = attrs.field() """User-facing name of the option, max 100 characters.""" @@ -270,14 +270,14 @@ class SelectMenuComponent(PartialComponent): """The minimum amount of options which must be chosen for this menu. This will be greater than or equal to 0 and will be less than or equal to - `SelectMenuComponent.max_values`. + [`hikari.components.SelectMenuComponent.max_values`][]. """ max_values: int = attrs.field(eq=False) """The minimum amount of options which can be chosen for this menu. This will be less than or equal to 25 and will be greater than or equal to - `SelectMenuComponent.min_values`. + [`hikari.components.SelectMenuComponent.min_values`][]. """ is_disabled: bool = attrs.field(eq=False) @@ -323,15 +323,15 @@ class TextInputComponent(PartialComponent): typing.Literal[ComponentType.CHANNEL_SELECT_MENU], typing.Literal[8], ] -"""Type hints of the `ComponentType` values which are valid for select menus. +"""Type hints of the [`hikari.components.ComponentType`][] values which are valid for select menus. The following values are valid for this: -* `ComponentType.TEXT_SELECT_MENU`/`3` -* `ComponentType.USER_SELECT_MENU`/`5` -* `ComponentType.ROLE_SELECT_MENU`/`6` -* `ComponentType.MENTIONABLE_SELECT_MENU`/`7` -* `ComponentType.CHANNEL_SELECT_MENU`/`8` +* [`hikari.components.ComponentType.TEXT_SELECT_MENU`][]/`3` +* [`hikari.components.ComponentType.USER_SELECT_MENU`][]/`5` +* [`hikari.components.ComponentType.ROLE_SELECT_MENU`][]/`6` +* [`hikari.components.ComponentType.MENTIONABLE_SELECT_MENU`][]`/`7` +* [`hikari.components.ComponentType.CHANNEL_SELECT_MENU`][]`/`8` """ SelectMenuTypes: typing.AbstractSet[SelectMenuTypesT] = frozenset( @@ -343,15 +343,15 @@ class TextInputComponent(PartialComponent): ComponentType.CHANNEL_SELECT_MENU, ) ) -"""Set of the `ComponentType` values which are valid for select menus. +"""Set of the [`hikari.components.ComponentType`][] values which are valid for select menus. The following values are included in this: -* `ComponentType.TEXT_SELECT_MENU` -* `ComponentType.USER_SELECT_MENU` -* `ComponentType.ROLE_SELECT_MENU` -* `ComponentType.MENTIONABLE_SELECT_MENU` -* `ComponentType.CHANNEL_SELECT_MENU` +* [`hikari.components.ComponentType.TEXT_SELECT_MENU`][] +* [`hikari.components.ComponentType.USER_SELECT_MENU`][] +* [`hikari.components.ComponentType.ROLE_SELECT_MENU`][] +* [`hikari.components.ComponentType.MENTIONABLE_SELECT_MENU`][] +* [`hikari.components.ComponentType.CHANNEL_SELECT_MENU`][] """ InteractiveButtonTypesT = typing.Union[ @@ -364,43 +364,43 @@ class TextInputComponent(PartialComponent): typing.Literal[ButtonStyle.DANGER], typing.Literal[4], ] -"""Type hints of the `ButtonStyle` values which are valid for interactive buttons. +"""Type hints of the [`hikari.components.ButtonStyle`][] values which are valid for interactive buttons. The following values are valid for this: -* `ButtonStyle.PRIMARY`/`1` -* `ButtonStyle.SECONDARY`/`2` -* `ButtonStyle.SUCCESS`/`3` -* `ButtonStyle.DANGER`/`4` +* [`hikari.components.ButtonStyle.PRIMARY`][] +* [`hikari.components.ButtonStyle.SECONDARY`][] +* [`hikari.components.ButtonStyle.SUCCESS`][] +* [`hikari.components.ButtonStyle.DANGER`][] """ InteractiveButtonTypes: typing.AbstractSet[InteractiveButtonTypesT] = frozenset( [ButtonStyle.PRIMARY, ButtonStyle.SECONDARY, ButtonStyle.SUCCESS, ButtonStyle.DANGER] ) -"""Set of the `ButtonType` which are valid for interactive buttons. +"""Set of the [`hikari.components.ButtonStyle`][] which are valid for interactive buttons. The following values are included in this: -* `ButtonStyle.PRIMARY` -* `ButtonStyle.SECONDARY` -* `ButtonStyle.SUCCESS` -* `ButtonStyle.DANGER` +* [`hikari.components.ButtonStyle.PRIMARY`][] +* [`hikari.components.ButtonStyle.SECONDARY`][] +* [`hikari.components.ButtonStyle.SUCCESS`][] +* [`hikari.components.ButtonStyle.DANGER`][] """ MessageComponentTypesT = typing.Union[ButtonComponent, SelectMenuComponent] -"""Type hint of the `PartialComponent` that be contained in a `MessageActionRowComponent`. +"""Type hint of the [`hikari.components.PartialComponent`][] that be contained in a [`hikari.components.PartialComponent`][]. The following values are valid for this: -* `ButtonComponent` -* `SelectMenuComponent` +* [`hikari.components.ButtonComponent`][] +* [`hikari.components.SelectMenuComponent`][] """ ModalComponentTypesT = TextInputComponent -"""Type hint of the `PartialComponent` that be contained in a `ModalActionRowComponent`. +"""Type hint of the [`hikari.components.PartialComponent`][] that be contained in a [`hikari.components.PartialComponent`][]. The following values are valid for this: -* `TextInputComponent` +* [`hikari.components.TextInputComponent`][] """ MessageActionRowComponent = ActionRowComponent[MessageComponentTypesT] diff --git a/hikari/embeds.py b/hikari/embeds.py index 6a2eeb1645..0b2d1ae7ff 100644 --- a/hikari/embeds.py +++ b/hikari/embeds.py @@ -84,12 +84,12 @@ def stream( ---------- executor : typing.Optional[concurrent.futures.Executor] The executor to run in for blocking operations. - If `None`, then the default executor is used for the + If [`None`][], then the default executor is used for the current event loop. head_only : bool - Defaults to `False`. If `True`, then the - implementation may only retrieve HEAD information if supported. - This currently only has any effect for web requests. + If [`True`][], then the implementation may only retrieve + HEAD information if supported. This currently only has + any effect for web requests. """ return self.resource.stream(executor=executor, head_only=head_only) @@ -99,9 +99,9 @@ class EmbedResourceWithProxy(EmbedResource): """Resource with a corresponding proxied element.""" proxy_resource: typing.Optional[files.Resource[files.AsyncReader]] = attrs.field(default=None, repr=False) - """The proxied version of the resource, or `None` if not present. + """The proxied version of the resource, or [`None`][] if not present. - .. note:: + !!! note This field cannot be set by bots or webhooks while sending an embed and will be ignored during serialization. Expect this to be populated on any received embed attached to a message event. @@ -110,13 +110,13 @@ class EmbedResourceWithProxy(EmbedResource): @property @typing.final def proxy_url(self) -> typing.Optional[str]: - """Proxied URL of this embed resource if applicable, else `None`.""" + """Proxied URL of this embed resource if applicable, else [`None`][].""" return self.proxy_resource.url if self.proxy_resource else None @property @typing.final def proxy_filename(self) -> typing.Optional[str]: - """File name of the proxied version of this embed resource if applicable, else `None`.""" + """File name of the proxied version of this embed resource if applicable, else [`None`][].""" return self.proxy_resource.filename if self.proxy_resource else None @@ -128,10 +128,10 @@ class EmbedFooter: # Discord says this is never None. We know that is invalid because Discord.py # sets it to None. Seems like undocumented behaviour again. text: typing.Optional[str] = attrs.field(default=None, repr=True) - """The footer text, or `None` if not present.""" + """The footer text, or [`None`][] if not present.""" icon: typing.Optional[EmbedResourceWithProxy] = attrs.field(default=None, repr=True) - """The URL of the footer icon, or `None` if not present.""" + """The URL of the footer icon, or [`None`][] if not present.""" @attrs.define(hash=False, kw_only=True, weakref_slot=False) @@ -139,18 +139,18 @@ class EmbedImage(EmbedResourceWithProxy): """Represents an embed image.""" height: typing.Optional[int] = attrs.field(default=None, repr=False) - """The height of the image, if present and known, otherwise `None`. + """The height of the image, if present and known, otherwise [`None`][]. - .. note:: + !!! note This field cannot be set by bots or webhooks while sending an embed and will be ignored during serialization. Expect this to be populated on any received embed attached to a message event. """ width: typing.Optional[int] = attrs.field(default=None, repr=False) - """The width of the image, if present and known, otherwise `None`. + """The width of the image, if present and known, otherwise [`None`][]. - .. note:: + !!! note This field cannot be set by bots or webhooks while sending an embed and will be ignored during serialization. Expect this to be populated on any received embed attached to a message event. @@ -161,7 +161,7 @@ class EmbedImage(EmbedResourceWithProxy): class EmbedVideo(EmbedResourceWithProxy): """Represents an embed video. - .. note:: + !!! note This object cannot be set by bots or webhooks while sending an embed and will be ignored during serialization. Expect this to be populated on any received embed attached to a message event with a video attached. @@ -182,7 +182,7 @@ class yourself.** class EmbedProvider: """Represents an embed provider. - .. note:: + !!! note This object cannot be set by bots or webhooks while sending an embed and will be ignored during serialization. Expect this to be populated on any received embed attached to a message event provided by an external @@ -205,16 +205,16 @@ class EmbedAuthor: """Represents an author of an embed.""" name: typing.Optional[str] = attrs.field(default=None, repr=True) - """The name of the author, or `None` if not specified.""" + """The name of the author, or [`None`][] if not specified.""" url: typing.Optional[str] = attrs.field(default=None, repr=True) """The URL that the author's name should act as a hyperlink to. - This may be `None` if no hyperlink on the author's name is specified. + This may be [`None`][] if no hyperlink on the author's name is specified. """ icon: typing.Optional[EmbedResourceWithProxy] = attrs.field(default=None, repr=False) - """The author's icon, or `None` if not present.""" + """The author's icon, or [`None`][] if not present.""" @attrs_extensions.with_copy @@ -234,9 +234,9 @@ class EmbedField: # in the constructor for `_inline`. @property def is_inline(self) -> bool: - """Return `True` if the field should display inline. + """Whether the field should display inline. - Defaults to `False`. + Defaults to [`False`][]. """ return self._inline @@ -289,7 +289,7 @@ def from_received_embed( ) -> Embed: """Generate an embed from the given attributes. - .. warning:: + !!! warning **This function is for internal use only!** """ # Create an empty instance without the overhead of invoking the regular @@ -351,7 +351,7 @@ def __init__( def title(self) -> typing.Optional[str]: """Return the title of the embed. - This will be `None` if not set. + This will be [`None`][] if not set. """ return self._title @@ -363,7 +363,7 @@ def title(self, value: typing.Any) -> None: def description(self) -> typing.Optional[str]: """Return the description of the embed. - This will be `None` if not set. + This will be [`None`][] if not set. """ return self._description @@ -375,7 +375,7 @@ def description(self, value: typing.Any) -> None: def url(self) -> typing.Optional[str]: """Return the URL of the embed title. - This will be `None` if not set. + This will be [`None`][] if not set. """ return self._url @@ -387,7 +387,7 @@ def url(self, value: typing.Optional[str]) -> None: def color(self) -> typing.Optional[colors.Color]: """Return the colour of the embed. - This will be `None` if not set. + This will be [`None`][] if not set. """ return self._color @@ -400,7 +400,7 @@ def color(self, value: typing.Optional[colors.Colorish]) -> None: # Alias. @property def colour(self) -> typing.Optional[colors.Color]: - """Alias of `color`.""" + """Alias of [`hikari.colors.Color`][].""" return self._color # Alias. @@ -414,21 +414,20 @@ def colour(self, value: typing.Optional[colors.Colorish]) -> None: def timestamp(self) -> typing.Optional[datetime.datetime]: """Return the timestamp of the embed. - This will be `None` if not set. + This will be [`None`][] if not set. - .. warning:: + !!! warning Setting a non-timezone-aware datetime will result in a warning being raised. This is done due to potential confusion caused by Discord requiring a UTC timestamp for this field. Any non-timezone aware timestamp is interpreted as using the system's current - timezone instead. Thus, using `datetime.datetime.utcnow` will + timezone instead. Thus, using [`datetime.datetime.utcnow`][] will result in a potentially incorrect timezone being set. To generate a timezone aware timestamp, use one of the following snippets: - .. code-block:: python - + ```py # Use UTC. >>> datetime.datetime.now(tz=datetime.timezone.utc) datetime.datetime(2020, 6, 5, 18, 29, 56, 424744, tzinfo=datetime.timezone.utc) @@ -436,6 +435,7 @@ def timestamp(self) -> typing.Optional[datetime.datetime]: # Use your current timezone. >>> datetime.datetime.now().astimezone() datetime.datetime(2020, 7, 7, 8, 57, 9, 775328, tzinfo=..., 'BST')) + ``` By specifying a timezone, Hikari can automatically adjust the given time to UTC without you needing to think about it. @@ -444,8 +444,7 @@ def timestamp(self) -> typing.Optional[datetime.datetime]: one by specifying a timezone. Hikari will detect any difference in timezone if the timestamp is non timezone-naive and fix it for you: - .. code-block:: python - + ```py # I am British, and it is June, so we are in daylight saving # (UTC+1 or GMT+1, specifically). >>> import datetime @@ -465,12 +464,13 @@ def timestamp(self) -> typing.Optional[datetime.datetime]: # explicitly specified, Hikari will convert it to UTC for you when # you send the embed. >>> ... + ``` - A library on PyPI called [tzlocal](...) also exists that may be useful - to you if you need to get your local timezone for any reason: - - .. code-block:: python + A library on PyPI called [tzlocal](https://pypi.org/project/tzlocal/) + also exists that may be useful to you if you need to get your local + timezone for any reason: + ```py >>> import datetime >>> import tzlocal @@ -488,6 +488,7 @@ def timestamp(self) -> typing.Optional[datetime.datetime]: datetime.datetime(2020, 6, 5, 18, 38, 27, 863990, tzinfo=datetime.timezone.utc) >>> dt.astimezone(tzlocal.get_localzone()) datetime.datetime(2020, 6, 5, 19, 38, 27, 863990, tzinfo=) + ``` ...this is not required, but you may find it more useful if using the timestamps in debug logs, for example. @@ -535,7 +536,7 @@ def __warn_naive_datetime() -> None: def footer(self) -> typing.Optional[EmbedFooter]: """Return the footer of the embed. - Will be `None` if not set. + Will be [`None`][] if not set. """ return self._footer @@ -543,10 +544,10 @@ def footer(self) -> typing.Optional[EmbedFooter]: def image(self) -> typing.Optional[EmbedImage]: """Return the image set in the embed. - Will be `None` if not set. + Will be [`None`][] if not set. - .. note:: - Use `set_image` to update this value. + !!! note + Use [`hikari.embeds.Embed.set_image`][] to update this value. """ return self._image @@ -554,10 +555,10 @@ def image(self) -> typing.Optional[EmbedImage]: def thumbnail(self) -> typing.Optional[EmbedImage]: """Return the thumbnail set in the embed. - Will be `None` if not set. + Will be [`None`][] if not set. - .. note:: - Use `set_thumbnail` to update this value. + !!! note + Use [`hikari.embeds.Embed.set_thumbnail`][] to update this value. """ return self._thumbnail @@ -565,9 +566,9 @@ def thumbnail(self) -> typing.Optional[EmbedImage]: def video(self) -> typing.Optional[EmbedVideo]: """Return the video to show in the embed. - Will be `None` if not set. + Will be [`None`][] if not set. - .. note:: + !!! note This object cannot be set by bots or webhooks while sending an embed and will be ignored during serialization. Expect this to be populated on any received embed attached to a message event with a @@ -579,9 +580,9 @@ def video(self) -> typing.Optional[EmbedVideo]: def provider(self) -> typing.Optional[EmbedProvider]: """Return the provider to show in the embed. - Will be `None` if not set. + Will be [`None`][] if not set. - .. note:: + !!! note This object cannot be set by bots or webhooks while sending an embed and will be ignored during serialization. Expect this to be populated on any received embed attached to a message event with a @@ -593,10 +594,10 @@ def provider(self) -> typing.Optional[EmbedProvider]: def author(self) -> typing.Optional[EmbedAuthor]: """Return the author to show in the embed. - Will be `None` if not set. + Will be [`None`][] if not set. - .. note:: - Use `set_author` to update this value. + !!! note + Use [`hikari.embeds.Embed.set_author`][] to update this value. """ return self._author @@ -604,9 +605,9 @@ def author(self) -> typing.Optional[EmbedAuthor]: def fields(self) -> typing.Sequence[EmbedField]: """Return the sequence of fields in the embed. - .. note:: - Use `add_field` to add a new field, `edit_field` to edit an existing - field, or `remove_field` to remove a field. + !!! note + Use [`hikari.embeds.Embed.add_field`][] to add a new field, [`hikari.embeds.Embed.edit_field`][] to edit an existing + field, or [`hikari.embeds.Embed.remove_field`][] to remove a field. """ return self._fields if self._fields else [] @@ -630,20 +631,20 @@ def set_author( This can be many different things, to aid in convenience. - - If `None`, nothing is set. - - If a `pathlib.PurePath` or `str` to a valid URL, the URL + - If [`None`][], nothing is set. + - If a [`pathlib.PurePath`][] or [`str`][] to a valid URL, the URL is linked to directly. - - Subclasses of `hikari.files.WebResource` such as - `hikari.files.URL`, - `hikari.messages.Attachment`, - `hikari.emojis.Emoji`, - `EmbedResource`, etc will have their URL linked to directly. + - Subclasses of [`hikari.files.WebResource`][] such as + [`hikari.files.URL`][], + [`hikari.messages.Attachment`][], + [`hikari.emojis.Emoji`][], + [`hikari.embeds.EmbedResource`][], etc will have their URL linked to directly. this field. - - If a `hikari.files.Bytes` is passed, or a `str` + - If a [`hikari.files.Bytes`][] is passed, or a [`str`][] that contains a valid data URI is passed, then this is uploaded as an attachment and linked into the embed. - - If a `hikari.files.File`, `pathlib.PurePath` or - `str` that is an absolute or relative path to a file + - 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 linked into the embed. @@ -667,26 +668,26 @@ def set_footer(self, text: typing.Optional[str], *, icon: typing.Optional[files. ---------- text : typing.Optional[str] The mandatory text string to set in the footer. - If `None`, the footer is removed. + If [`None`][], the footer is removed. icon : typing.Optional[hikari.files.Resourceish] The optional image to show next to the embed footer. This can be many different things, to aid in convenience. - - If `None`, nothing is set. - - If a `pathlib.PurePath` or `str` to a valid URL, the URL + - If [`None`][], nothing is set. + - If a [`pathlib.PurePath`][] or [`str`][] to a valid URL, the URL is linked to directly. - - Subclasses of `hikari.files.WebResource` such as - `hikari.files.URL`, - `hikari.messages.Attachment`, - `hikari.emojis.Emoji`, - `EmbedResource`, etc will have their URL linked to directly. + - Subclasses of [`hikari.files.WebResource`][] such as + [`hikari.files.URL`][], + [`hikari.messages.Attachment`][], + [`hikari.emojis.Emoji`][], + [`hikari.embeds.EmbedResource`][], etc. will have their URL linked to directly. this field. - - If a `hikari.files.Bytes` is passed, or a `str` + - If a [`hikari.files.Bytes`][] is passed, or a [`str`][] that contains a valid data URI is passed, then this is uploaded as an attachment and linked into the embed. - - If a `hikari.files.File`, `pathlib.PurePath` or - `str` that is an absolute or relative path to a file + - 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 linked into the embed. @@ -719,20 +720,20 @@ def set_image(self, image: typing.Optional[files.Resourceish] = None, /) -> Embe This can be many different things, to aid in convenience. - - If `None`, nothing is set. - - If a `pathlib.PurePath` or `str` to a valid URL, the URL + - If [`None`][], nothing is set. + - If a [`pathlib.PurePath`][] or [`str`][] to a valid URL, the URL is linked to directly. - - Subclasses of `hikari.files.WebResource` such as - `hikari.files.URL`, - `hikari.messages.Attachment`, - `hikari.emojis.Emoji`, - `EmbedResource`, etc will have their URL linked to directly. + - Subclasses of [`hikari.files.WebResource`][] such as + [`hikari.files.URL`][], + [`hikari.messages.Attachment`][], + [`hikari.emojis.Emoji`][], + [`hikari.embeds.EmbedResource`][], etc will have their URL linked to directly. this field. - - If a `hikari.files.Bytes` is passed, or a `str` + - If a [`hikari.files.Bytes`][] is passed, or a [`str`][] that contains a valid data URI is passed, then this is uploaded as an attachment and linked into the embed. - - If a `hikari.files.File`, `pathlib.PurePath` or - `str` that is an absolute or relative path to a file + - 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 linked into the embed. @@ -759,19 +760,19 @@ def set_thumbnail(self, image: typing.Optional[files.Resourceish] = None, /) -> This can be many different things, to aid in convenience. - - If `None`, nothing is set. - - If a `pathlib.PurePath` or `str` to a valid URL, the URL + - If [`None`][], nothing is set. + - If a [`pathlib.PurePath`][] or [`str`][] to a valid URL, the URL is linked to directly. - - Subclasses of `hikari.files.WebResource` such as - `hikari.files.URL`, - `hikari.messages.Attachment`, - `hikari.emojis.Emoji`, - `EmbedResource`, etc will have their URL linked to directly. - - If a `hikari.files.Bytes` is passed, or a `str` + - Subclasses of [`hikari.files.WebResource`][] such as + [`hikari.files.URL`][], + [`hikari.messages.Attachment`][], + [`hikari.emojis.Emoji`][], + [`hikari.embeds.EmbedResource`][], etc will have their URL linked to directly. + - If a [`hikari.files.Bytes`][] is passed, or a [`str`][] that contains a valid data URI is passed, then this is uploaded as an attachment and linked into the embed. - - If a `hikari.files.File`, `pathlib.PurePath` or - `str` that is an absolute or relative path to a file + - 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 linked into the embed. @@ -803,9 +804,9 @@ def add_field(self, name: str, value: str, *, inline: bool = False) -> Embed: Other Parameters ---------------- inline : bool - If `True`, the embed field may be shown "inline" on some - Discord clients with other fields. If `False`, it is always placed - on a separate line. This will default to `False`. + If [`True`][], the embed field may be shown "inline" on some + Discord clients with other fields. If [`False`][], it is always placed + on a separate line. This will default to [`False`][]. Returns ------- @@ -836,14 +837,14 @@ def edit_field( Other Parameters ---------------- name : hikari.undefined.UndefinedOr[str] - The new field name to use. If left to the default (`undefined`), + The new field name to use. If left to the default ([`hikari.undefined.UNDEFINED`][]), then it will not be changed. value : hikari.undefined.UndefinedOr[str] - The new field value to use. If left to the default (`undefined`), + The new field value to use. If left to the default ([`hikari.undefined.UNDEFINED`][]), then it will not be changed. inline : hikari.undefined.UndefinedOr[bool] - `True` to inline the field, or `False` to force - it to be on a separate line. If left to the default (`undefined`), + [`True`][] to inline the field, or [`False`][] to force + it to be on a separate line. If left to the default ([`hikari.undefined.UNDEFINED`][]), then it will not be changed. Returns diff --git a/hikari/emojis.py b/hikari/emojis.py index 3a1d11eaa1..8d12427ae7 100644 --- a/hikari/emojis.py +++ b/hikari/emojis.py @@ -53,9 +53,9 @@ class Emoji(files.WebResource, abc.ABC): """Base class for all emojis. Any emoji implementation supports being used as a - `hikari.files.Resource` when uploading an attachment to the API. + [`hikari.files.Resource`][] when uploading an attachment to the API. This is achieved in the same way as using a - `hikari.files.WebResource` would achieve this. + [`hikari.files.WebResource`][] would achieve this. """ __slots__: typing.Sequence[str] = () @@ -92,8 +92,8 @@ def parse(cls, string: str, /) -> Emoji: Returns ------- Emoji - The parsed emoji object. This will be a `CustomEmoji` if a custom - emoji mention, or a `UnicodeEmoji` otherwise. + The parsed emoji object. This will be a [`hikari.emojis.CustomEmoji`][] if a custom + emoji mention, or a [`hikari.emojis.UnicodeEmoji`][] otherwise. Raises ------ @@ -108,7 +108,7 @@ def parse(cls, string: str, /) -> Emoji: class UnicodeEmoji(str, Emoji): """Represents a unicode emoji. - .. warning:: + !!! warning A word of warning if you try to upload this emoji as a file attachment. While this emoji type can be used to upload the Twemoji representations @@ -116,7 +116,7 @@ class UnicodeEmoji(str, Emoji): Discord's implementation and official Twemoji bindings is very flaky. Responsible implementations relying on this behaviour will be implemented to expect this behaviour in the form of - `hikari.errors.NotFoundError` exceptions being raised when a mismatch may + [`hikari.errors.NotFoundError`][] exceptions being raised when a mismatch may occur. It is also likely that this will change in the future without notice, so you will likely be relying on flaky behaviour. @@ -178,11 +178,11 @@ def url(self) -> str: Examples -------- - .. code-block:: python - + ```py >>> emoji = hikari.UnicodeEmoji("\N{OK HAND SIGN}") >>> emoji.url 'https://raw.githubusercontent.com/discord/twemoji/master/assets/72x72/1f44c.png' + ``` """ return _TWEMOJI_PNG_BASE_URL + self.filename @@ -245,14 +245,14 @@ class CustomEmoji(snowflakes.Unique, Emoji): This is a custom emoji that is from a guild you might not be part of. All CustomEmoji objects and their derivatives act as valid - `hikari.files.Resource` objects. This means you can use them as a + [`hikari.files.Resource`][] objects. This means you can use them as a file when sending a message. >>> emojis = await bot.rest.fetch_guild_emojis(12345) >>> picks = random.choices(emojis, 5) >>> await event.respond(files=picks) - .. warning:: + !!! warning Discord will not provide information on whether these emojis are animated or not when a reaction is removed and an event is fired. This is problematic if you need to try and determine the emoji that was @@ -329,7 +329,7 @@ def parse(cls, string: str, /) -> CustomEmoji: class KnownCustomEmoji(CustomEmoji): """Represents an emoji that is known from a guild the bot is in. - This is a specialization of `CustomEmoji` that is from a guild that you + This is a specialization of [`hikari.emojis.CustomEmoji`][] that is from a guild that you _are_ part of. As a result, it contains a lot more information with it. """ @@ -350,8 +350,8 @@ class KnownCustomEmoji(CustomEmoji): user: typing.Optional[users.User] = attrs.field(eq=False, hash=False, repr=False) """The user that created the emoji. - .. note:: - This will be `None` if you are missing the `MANAGE_EMOJIS_AND_STICKERS` + !!! note + This will be [`None`][] if you are missing the [`hikari.permissions.Permissions.MANAGE_GUILD_EXPRESSIONS`][] permission in the server the emoji is from. """ @@ -364,5 +364,5 @@ class KnownCustomEmoji(CustomEmoji): is_available: bool = attrs.field(eq=False, hash=False, repr=False) """Whether this emoji can currently be used. - May be `False` due to a loss of Sever Boosts on the emoji's guild. + May be [`False`][] due to a loss of Sever Boosts on the emoji's guild. """ diff --git a/hikari/errors.py b/hikari/errors.py index aa33d3d472..6adcf3c69e 100644 --- a/hikari/errors.py +++ b/hikari/errors.py @@ -74,7 +74,7 @@ class HikariError(RuntimeError): Any exceptions should derive from this. - .. note:: + !!! note You should never initialize this exception directly. """ @@ -87,7 +87,7 @@ class HikariWarning(RuntimeWarning): Any warnings should derive from this. - .. note:: + !!! note You should never initialize this warning directly. """ @@ -172,7 +172,7 @@ class ShardCloseCode(int, enums.Enum): @property def is_standard(self) -> bool: - """Return `True` if this is a standard code.""" + """Return [`True`][] if this is a standard code.""" return (self.value // 1000) == 1 @@ -192,10 +192,10 @@ class GatewayServerClosedConnectionError(GatewayError): """Return the close code that was received, if there is one.""" can_reconnect: bool = attrs.field(default=False) - """Return `True` if we can recover from this closure. + """Return [`True`][] if we can recover from this closure. - If `True`, it will try to reconnect after this is raised rather - than it being propagated to the caller. If `False`, this will + If [`True`][], it will try to reconnect after this is raised rather + than it being propagated to the caller. If [`False`][], this will be raised, thus stopping the application unless handled explicitly by the user. """ @@ -222,7 +222,7 @@ class HTTPResponseError(HTTPError): status: typing.Union[http.HTTPStatus, int] = attrs.field() """The HTTP status code for the response. - This will be `int` if it's outside the range of status codes in the HTTP + This will be [`int`][] if it's outside the range of status codes in the HTTP specification (e.g. one of Cloudflare's non-standard status codes). """ @@ -360,7 +360,7 @@ class NotFoundError(ClientHTTPResponseError): class RateLimitTooLongError(HTTPError): """Internal error raised if the wait for a rate limit is too long. - This is similar to `asyncio.TimeoutError` in the way that it is used, + This is similar to [`asyncio.TimeoutError`][] in the way that it is used, but this will be raised pre-emptively and immediately if the period of time needed to wait is greater than a user-defined limit. diff --git a/hikari/events/base_events.py b/hikari/events/base_events.py index f26ba0d67f..690e81756b 100644 --- a/hikari/events/base_events.py +++ b/hikari/events/base_events.py @@ -160,7 +160,7 @@ def decorator(cls: _T) -> _T: doc = inspect.getdoc(cls) or "" doc += ( "\n" - ".. warning::\n" + "!!! warning\n" " Any exceptions raised by handlers for this event will be dumped to the\n" " application logger and silently discarded, preventing recursive loops\n" " produced by faulty exception event handling. Thus, it is imperative\n" @@ -174,7 +174,7 @@ def decorator(cls: _T) -> _T: def is_no_recursive_throw_event(obj: typing.Union[_T, typing.Type[_T]]) -> bool: - """Return True if this event is marked as `___norecursivethrow___`.""" + """Whether the event is marked as `___norecursivethrow___`.""" result = getattr(obj, NO_RECURSIVE_THROW_attrs, False) assert isinstance(result, bool) return result @@ -188,13 +188,13 @@ def is_no_recursive_throw_event(obj: typing.Union[_T, typing.Type[_T]]) -> bool: @attrs_extensions.with_copy @attrs.define(kw_only=True, weakref_slot=False) class ExceptionEvent(Event, typing.Generic[EventT]): - """Event that is raised when another event handler raises an `Exception`. + """Event that is raised when another event handler raises an [`Exception`][]. - .. note:: - Only exceptions that derive from `Exception` will be caught. + !!! note + Only exceptions that derive from [`Exception`][] will be caught. Other exceptions outside this range will propagate past this callback. This prevents event handlers interfering with critical exceptions - such as `KeyboardError` which would have potentially undesired + such as [`KeyboardInterrupt`][] which would have potentially undesired side-effects on the application runtime. """ @@ -216,7 +216,7 @@ def app(self) -> traits.RESTAware: def shard(self) -> typing.Optional[gateway_shard.GatewayShard]: """Shard that received the event, if there was one associated. - This may be `None` if no specific shard was the cause of this + This may be [`None`][] if no specific shard was the cause of this exception (e.g. when starting up or shutting down). """ shard = getattr(self.failed_event, "shard", None) @@ -226,9 +226,9 @@ def shard(self) -> typing.Optional[gateway_shard.GatewayShard]: @property def exc_info(self) -> typing.Tuple[typing.Type[Exception], Exception, typing.Optional[types.TracebackType]]: - """Exception triplet that follows the same format as `sys.exc_info`. + """Exception triplet that follows the same format as [`sys.exc_info`][]. - The `sys.exc_info` triplet consists of the exception type, the exception + The [`sys.exc_info`][] triplet consists of the exception type, the exception instance, and the traceback of the exception. """ return type(self.exception), self.exception, self.exception.__traceback__ diff --git a/hikari/events/channel_events.py b/hikari/events/channel_events.py index dfbc484c01..5c3d4d2e4b 100644 --- a/hikari/events/channel_events.py +++ b/hikari/events/channel_events.py @@ -89,14 +89,14 @@ def channel_id(self) -> snowflakes.Snowflake: async def fetch_channel(self) -> channels.PartialChannel: """Perform an API call to fetch the details about this channel. - .. note:: - For `GuildChannelDeleteEvent` events, this will always raise + !!! note + For [`hikari.events.channel_events.GuildChannelDeleteEvent`][] events, this will always raise an exception, since the channel will have already been removed. Returns ------- hikari.channels.PartialChannel - A derivative of `hikari.channels.PartialChannel`. The actual type + A derivative of [`hikari.channels.PartialChannel`][]. The actual type will vary depending on the type of channel this event concerns. Raises @@ -104,7 +104,7 @@ async def fetch_channel(self) -> channels.PartialChannel: hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -129,13 +129,13 @@ def guild_id(self) -> snowflakes.Snowflake: def get_guild(self) -> typing.Optional[guilds.GatewayGuild]: """Get the cached guild that this event relates to, if known. - If not, return `None`. + If not, return [`None`][]. Returns ------- typing.Optional[hikari.guilds.GatewayGuild] The gateway guild this event relates to, if known. Otherwise - this will return `None`. + this will return [`None`][]. """ if not isinstance(self.app, traits.CacheAware): return None @@ -169,13 +169,13 @@ async def fetch_guild(self) -> guilds.RESTGuild: def get_channel(self) -> typing.Optional[channels.PermissibleGuildChannel]: """Get the cached channel that this event relates to, if known. - If not, return `None`. + If not, return [`None`][]. Returns ------- typing.Optional[hikari.channels.GuildChannel] The cached channel this event relates to. If not known, this - will return `None` instead. + will return [`None`][] instead. """ if not isinstance(self.app, traits.CacheAware): return None @@ -185,14 +185,14 @@ def get_channel(self) -> typing.Optional[channels.PermissibleGuildChannel]: async def fetch_channel(self) -> channels.GuildChannel: """Perform an API call to fetch the details about this channel. - .. note:: - For `GuildChannelDeleteEvent` events, this will always raise + !!! note + For [`hikari.events.channel_events.GuildChannelDeleteEvent`][] events, this will always raise an exception, since the channel will have already been removed. Returns ------- hikari.channels.GuildChannel - A derivative of `hikari.channels.GuildChannel`. The + A derivative of [`hikari.channels.GuildChannel`][]. The actual type will vary depending on the type of channel this event concerns. @@ -201,7 +201,7 @@ async def fetch_channel(self) -> channels.GuildChannel: hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -223,14 +223,14 @@ class DMChannelEvent(ChannelEvent, abc.ABC): async def fetch_channel(self) -> channels.PrivateChannel: """Perform an API call to fetch the details about this channel. - .. note:: - For `GuildChannelDeleteEvent` events, this will always raise + !!! note + For [`hikari.events.channel_events.GuildChannelDeleteEvent`][] events, this will always raise an exception, since the channel will have already been removed. Returns ------- hikari.channels.PrivateChannel - A derivative of `hikari.channels.PrivateChannel`. The actual + A derivative of [`hikari.channels.PrivateChannel`][]. The actual type will vary depending on the type of channel this event concerns. @@ -239,7 +239,7 @@ async def fetch_channel(self) -> channels.PrivateChannel: hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `VIEW_CHANNEL` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -293,7 +293,7 @@ class GuildChannelUpdateEvent(GuildChannelEvent): old_channel: typing.Optional[channels.PermissibleGuildChannel] = attrs.field(repr=True) """The old guild channel object. - This will be `None` if the channel missing from the cache. + This will be [`None`][] if the channel missing from the cache. """ channel: channels.PermissibleGuildChannel = attrs.field(repr=True) @@ -358,7 +358,7 @@ class PinsUpdateEvent(ChannelEvent, abc.ABC): def last_pin_timestamp(self) -> typing.Optional[datetime.datetime]: """Datetime of when the most recent message was pinned in the channel. - Will be `None` if nothing is pinned or the information is + Will be [`None`][] if nothing is pinned or the information is unavailable. """ @@ -369,7 +369,7 @@ async def fetch_channel(self) -> channels.TextableChannel: Returns ------- hikari.channels.TextableChannel - A derivative of `hikari.channels.TextableChannel`. The actual + A derivative of [`hikari.channels.TextableChannel`][]. The actual type will vary depending on the type of channel this event concerns. """ @@ -409,13 +409,13 @@ class GuildPinsUpdateEvent(PinsUpdateEvent, GuildChannelEvent): def get_channel(self) -> typing.Optional[channels.PermissibleGuildChannel]: """Get the cached channel that this event relates to, if known. - If not, return `None`. + If not, return [`None`][]. Returns ------- typing.Optional[hikari.channels.TextableGuildChannel] The cached channel this event relates to. If not known, this - will return `None` instead. + will return [`None`][] instead. """ channel = super().get_channel() assert channel is None or isinstance(channel, channels.PermissibleGuildChannel) @@ -427,7 +427,7 @@ async def fetch_channel(self) -> channels.TextableGuildChannel: Returns ------- hikari.channels.TextableGuildChannel - A derivative of `hikari.channels.TextableGuildChannel`. The actual + A derivative of [`hikari.channels.TextableGuildChannel`][]. The actual type will vary depending on the type of channel this event concerns. @@ -436,7 +436,7 @@ async def fetch_channel(self) -> channels.TextableGuildChannel: hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `VIEW_CHANNEL` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -474,7 +474,7 @@ async def fetch_channel(self) -> channels.DMChannel: Returns ------- hikari.channels.DMChannel - A derivative of `hikari.channels.DMChannel`. The actual + A derivative of [`hikari.channels.DMChannel`][]. The actual type will vary depending on the type of channel this event concerns. @@ -586,7 +586,7 @@ class InviteDeleteEvent(InviteEvent): old_invite: typing.Optional[invites.InviteWithMetadata] = attrs.field() """Object of the old cached invite. - This will be `None` if the invite is missing from the cache. + This will be [`None`][] if the invite is missing from the cache. """ if typing.TYPE_CHECKING: @@ -631,7 +631,7 @@ async def fetch_channel_webhooks(self) -> typing.Sequence[webhooks.PartialWebhoo hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_WEBHOOKS` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -655,7 +655,7 @@ async def fetch_guild_webhooks(self) -> typing.Sequence[webhooks.PartialWebhook] hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_WEBHOOKS` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission. hikari.errors.NotFoundError If the guild is not found. hikari.errors.RateLimitTooLongError @@ -686,14 +686,14 @@ def thread_id(self) -> snowflakes.Snowflake: async def fetch_channel(self) -> channels.GuildThreadChannel: """Perform an API call to fetch the details about this thread. - .. note:: - For `GuildThreadDeleteEvent` events, this will always raise + !!! note + For [`hikari.events.channel_events.GuildThreadDeleteEvent`][] events, this will always raise an exception, since the channel will have already been removed. Returns ------- hikari.channels.GuildThreadChannel - A derivative of `hikari.channels.GuildThreadChannel`. The + A derivative of [`hikari.channels.GuildThreadChannel`][]. The actual type will vary depending on the type of channel this event concerns. @@ -702,7 +702,7 @@ async def fetch_channel(self) -> channels.GuildThreadChannel: hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -850,7 +850,7 @@ class ThreadMembersUpdateEvent(GuildThreadEvent): approximate_member_count: int = attrs.field(eq=False, hash=False, repr=True) """Approximate count of members in the thread channel. - .. warning:: + !!! warning This stops counting at 50 for threads created before 2022/06/01. """ @@ -863,13 +863,13 @@ class ThreadMembersUpdateEvent(GuildThreadEvent): guild_members: typing.Mapping[snowflakes.Snowflake, guilds.Member] = attrs.field() """Mapping of IDs to guild member objects of the added thread members. - Will only be filled if the `GUILD_MEMBERS` intent is declared. + Will only be filled if the [`hikari.intents.Intents.GUILD_MEMBERS`][] intent is declared. """ guild_presences: typing.Mapping[snowflakes.Snowflake, presences.MemberPresence] = attrs.field() """Mapping of IDs to guild presence objects of the added members. - Will only be filled if the `GUILD_PRESENCES` intent is declared. + Will only be filled if the [`hikari.intents.Intents.GUILD_PRESENCES`][] intent is declared. """ @@ -891,7 +891,7 @@ class ThreadListSyncEvent(shard_events.ShardEvent): channel_ids: typing.Optional[typing.Sequence[snowflakes.Snowflake]] = attrs.field() """IDs of the text channels threads are being synced for. - If this is `None` then threads are being synced for all text + If this is [`None`][] then threads are being synced for all text channels in the guild. This may contain channels that have no active threads as well to allow for diff --git a/hikari/events/guild_events.py b/hikari/events/guild_events.py index 06e86c12cf..2a2da96689 100644 --- a/hikari/events/guild_events.py +++ b/hikari/events/guild_events.py @@ -108,12 +108,12 @@ async def fetch_guild_preview(self) -> guilds.GuildPreview: def get_guild(self) -> typing.Optional[guilds.GatewayGuild]: """Get the cached guild that this event relates to, if known. - If not known, this will return `None` instead. + If not known, this will return [`None`][] instead. Returns ------- typing.Optional[hikari.guilds.GatewayGuild] - The guild this event relates to, or `None` if not known. + The guild this event relates to, or [`None`][] if not known. """ if not isinstance(self.app, traits.CacheAware): return None @@ -142,10 +142,10 @@ class GuildAvailableEvent(GuildVisibilityEvent): This will occur on startup or after outages. - .. note:: + !!! note Some fields like `members` and `presences` are included here but not on - the other `GuildUpdateEvent` and `GuildUnavailableEvent` guild visibility - event models. + the other [`hikari.events.guild_events.GuildUpdateEvent`][] and + [`hikari.events.guild_events.GuildUnavailableEvent`][] guild visibility event models. """ shard: gateway_shard.GatewayShard = attrs.field(metadata={attrs_extensions.SKIP_DEEP_COPY: True}) @@ -181,9 +181,9 @@ class GuildAvailableEvent(GuildVisibilityEvent): chunk_nonce: typing.Optional[str] = attrs.field(repr=False, default=None) """Nonce used to request the member chunks for this guild. - This will be `None` if no chunks were requested. + This will be [`None`][] if no chunks were requested. - .. note:: + !!! note This is a synthetic field. """ @@ -204,10 +204,10 @@ def guild_id(self) -> snowflakes.Snowflake: class GuildJoinEvent(GuildVisibilityEvent): """Event fired when the bot joins a new guild. - .. note:: + !!! note Some fields like `members` and `presences` are included here but not on - the other `GuildUpdateEvent` and `GuildUnavailableEvent` guild visibility - event models. + the other [`hikari.events.guild_events.GuildUpdateEvent`][] + and [`hikari.events.guild_events.GuildUnavailableEvent`][] guild visibility event models. """ shard: gateway_shard.GatewayShard = attrs.field(metadata={attrs_extensions.SKIP_DEEP_COPY: True}) @@ -243,9 +243,9 @@ class GuildJoinEvent(GuildVisibilityEvent): chunk_nonce: typing.Optional[str] = attrs.field(repr=False, default=None) """Nonce used to request the member chunks for this guild. - This will be `None` if no chunks were requested. + This will be [`None`][] if no chunks were requested. - .. note:: + !!! note This is a synthetic field. """ @@ -281,7 +281,7 @@ class GuildLeaveEvent(GuildVisibilityEvent): old_guild: typing.Optional[guilds.GatewayGuild] = attrs.field() """The old guild object. - This will be `None` if the guild missing from the cache. + This will be [`None`][] if the guild missing from the cache. """ if typing.TYPE_CHECKING: @@ -317,7 +317,7 @@ class GuildUpdateEvent(GuildEvent): old_guild: typing.Optional[guilds.GatewayGuild] = attrs.field() """The old guild object. - This will be `None` if the guild missing from the cache. + This will be [`None`][] if the guild missing from the cache. """ guild: guilds.GatewayGuild = attrs.field() @@ -438,7 +438,7 @@ class EmojisUpdateEvent(GuildEvent): old_emojis: typing.Optional[typing.Sequence[emojis_.KnownCustomEmoji]] = attrs.field() """Sequence of all old emojis in this guild. - This will be `None` if it's missing from the cache. + This will be [`None`][] if it's missing from the cache. """ emojis: typing.Sequence[emojis_.KnownCustomEmoji] = attrs.field() @@ -473,7 +473,7 @@ class StickersUpdateEvent(GuildEvent): old_stickers: typing.Optional[typing.Sequence[stickers_.GuildSticker]] = attrs.field() """Sequence of all old stickers in this guild. - This will be `None` if it's missing from the cache. + This will be [`None`][] if it's missing from the cache. """ stickers: typing.Sequence[stickers_.GuildSticker] = attrs.field() @@ -509,7 +509,7 @@ def id(self) -> snowflakes.Snowflake: async def fetch_integrations(self) -> typing.Sequence[guilds.Integration]: """Perform an API call to fetch some number of guild integrations. - .. warning:: + !!! warning The results of this are not clearly defined by Discord. The current behaviour appears to be that only the first 50 integrations actually get returned. Discord have made it clear that they are not willing @@ -632,7 +632,7 @@ class PresenceUpdateEvent(shard_events.ShardEvent): old_presence: typing.Optional[presences_.MemberPresence] = attrs.field() """The old member presence object. - This will be `None` if the member presence missing from the cache. + This will be [`None`][] if the member presence missing from the cache. """ presence: presences_.MemberPresence = attrs.field() @@ -644,7 +644,7 @@ class PresenceUpdateEvent(shard_events.ShardEvent): This is a partial user object that only contains the fields that were updated on the user profile. - Will be `None` if the user itself did not change. + Will be [`None`][] if the user itself did not change. This is always the case if the user only updated their member representation and did not change their user profile directly. """ @@ -670,7 +670,7 @@ def get_user(self) -> typing.Optional[users.User]: Returns ------- typing.Optional[hikari.users.User] - The full cached user, or `None` if not cached. + The full cached user, or [`None`][] if not cached. """ if not isinstance(self.app, traits.CacheAware): return None diff --git a/hikari/events/lifetime_events.py b/hikari/events/lifetime_events.py index 045e53285f..6f4e1eb489 100644 --- a/hikari/events/lifetime_events.py +++ b/hikari/events/lifetime_events.py @@ -46,18 +46,18 @@ class StartingEvent(base_events.Event): """Event that is triggered before the application connects to Discord. - This will only fire once per `bot.run` / `bot.start`, so is suitable for + This will only fire once per startup, so is suitable for opening database connections and other resources that need to be initialized within a coroutine function. - .. warning:: + !!! warning The application will not proceed to connect to Discord until all event handlers for this event have completed/terminated. This prevents the risk of race conditions occurring (e.g. allowing message events to try to access a database that has not yet connected fully). If you want to do something _after_ the application has initialized, you - should consider using `StartedEvent` instead. + should consider using [`hikari.events.lifetime_events.StartingEvent`][] instead. """ app: traits.RESTAware = attrs.field(metadata={attrs_extensions.SKIP_DEEP_COPY: True}) @@ -69,12 +69,12 @@ class StartingEvent(base_events.Event): class StartedEvent(base_events.Event): """Event that is triggered after the application has started. - This will only fire once per `bot.run` / `bot.start`, so is suitable for + This will only fire once per startup, so is suitable for opening database connections and other resources that need to be initialized within a coroutine function. If you want to do something _before_ the application connects, you should - consider using `StartingEvent` instead. + consider using [`hikari.events.lifetime_events.StartingEvent`][] instead. """ app: traits.RESTAware = attrs.field(metadata={attrs_extensions.SKIP_DEEP_COPY: True}) @@ -88,18 +88,18 @@ class StoppingEvent(base_events.Event): This will fire before the connection is physically disconnected. - This will only fire once per `bot.close`, so is suitable for + This will only fire once per close, so is suitable for closing database connections and other resources that need to be closed within a coroutine function. - .. warning:: + !!! warning The application will not proceed to disconnect from Discord until all event handlers for this event have completed/terminated. This prevents the risk of race conditions occurring from code that relies on a connection still being available to complete. If you want to do something _after_ the disconnection has occurred, you - should consider using `StoppedEvent` instead. + should consider using [`hikari.events.lifetime_events.StoppingEvent`][] instead. """ app: traits.RESTAware = attrs.field(metadata={attrs_extensions.SKIP_DEEP_COPY: True}) @@ -111,19 +111,19 @@ class StoppingEvent(base_events.Event): class StoppedEvent(base_events.Event): """Event that is triggered once the application has disconnected. - This will only fire once per `bot.close`, so is suitable for + This will only fire once per close, so is suitable for closing database connections and other resources that need to be closed within a coroutine function. - .. warning:: - The application will not proceed to leave the `bot.run` call until all + !!! warning + The application will not proceed to leave the run call until all event handlers for this event have completed/terminated. This prevents the risk of race conditions occurring where a script may terminate the process before a callback can occur. If you want to do something when the application is preparing to shut down, but _before_ any connection to Discord is closed, you should consider using - `StoppingEvent` instead. + [`hikari.events.lifetime_events.StoppingEvent`][] instead. """ app: traits.RESTAware = attrs.field(metadata={attrs_extensions.SKIP_DEEP_COPY: True}) diff --git a/hikari/events/member_events.py b/hikari/events/member_events.py index 57e120403c..893049ab7f 100644 --- a/hikari/events/member_events.py +++ b/hikari/events/member_events.py @@ -72,13 +72,13 @@ def user_id(self) -> snowflakes.Snowflake: def get_guild(self) -> typing.Optional[guilds.GatewayGuild]: """Get the cached view of the guild this member event occurred in. - If the guild itself is not cached, this will return `None`. + If the guild itself is not cached, this will return [`None`][]. Returns ------- typing.Optional[hikari.guilds.GatewayGuild] The guild that this event occurred in, if known, else - `None`. + [`None`][]. """ if not isinstance(self.app, traits.CacheAware): return None @@ -124,7 +124,7 @@ class MemberUpdateEvent(MemberEvent): old_member: typing.Optional[guilds.Member] = attrs.field() """The old member object. - This will be `None` if the member missing from the cache. + This will be [`None`][] if the member missing from the cache. """ member: guilds.Member = attrs.field() @@ -159,5 +159,5 @@ class MemberDeleteEvent(MemberEvent): old_member: typing.Optional[guilds.Member] = attrs.field() """The old member object. - This will be `None` if the member was missing from the cache. + This will be [`None`][] if the member was missing from the cache. """ diff --git a/hikari/events/message_events.py b/hikari/events/message_events.py index e854e47eee..673faeaf36 100644 --- a/hikari/events/message_events.py +++ b/hikari/events/message_events.py @@ -107,7 +107,7 @@ def channel_id(self) -> snowflakes.Snowflake: def content(self) -> typing.Optional[str]: """Content of the message. - The content of the message, if present. This will be `None` + The content of the message, if present. This will be [`None`][] if no content is present (e.g. if only an embed was sent). """ return self.message.content @@ -119,19 +119,19 @@ def embeds(self) -> typing.Sequence[embeds_.Embed]: @property def is_bot(self) -> bool: - """Return `True` if the message is from a bot.""" + """Return [`True`][] if the message is from a bot.""" return self.message.author.is_bot @property def is_human(self) -> bool: - """Return `True` if the message was created by a human.""" + """Return [`True`][] if the message was created by a human.""" # Not second-guessing some weird edge case will occur in the future with this, # so I am being safe rather than sorry. return not self.message.author.is_bot and self.message.webhook_id is None @property def is_webhook(self) -> bool: - """Return `True` if the message was created by a webhook.""" + """Return [`True`][] if the message was created by a webhook.""" return self.message.webhook_id is not None @property @@ -151,7 +151,8 @@ def message_id(self) -> snowflakes.Snowflake: class GuildMessageCreateEvent(MessageCreateEvent): """Event that is fired when a message is created within a guild. - This contains the full message in the internal `message` attribute. + This contains the full message in the internal + [`message`][hikari.events.message_events.GuildMessageCreateEvent.message] attribute. """ message: messages.Message = attrs.field() @@ -185,7 +186,7 @@ def get_channel(self) -> typing.Optional[channels.TextableGuildChannel]: ------- typing.Optional[hikari.channels.TextableGuildChannel] The channel that the message was sent in, if known and cached, - otherwise, `None`. + otherwise, [`None`][]. """ if not isinstance(self.app, traits.CacheAware): return None @@ -199,15 +200,15 @@ def get_channel(self) -> typing.Optional[channels.TextableGuildChannel]: def get_guild(self) -> typing.Optional[guilds.GatewayGuild]: """Get the cached guild that this event occurred in, if known. - .. note:: - This will require the `GUILDS` intent to be specified on start-up + !!! note + This will require the [`hikari.intents.Intents.GUILDS`][] intent to be specified on start-up in order to be known. Returns ------- typing.Optional[hikari.guilds.GatewayGuild] The guild that this event occurred in, if cached. Otherwise, - `None` instead. + [`None`][] instead. """ if not isinstance(self.app, traits.CacheAware): return None @@ -234,7 +235,8 @@ def get_member(self) -> typing.Optional[guilds.Member]: class DMMessageCreateEvent(MessageCreateEvent): """Event that is fired when a message is created within a DM. - This contains the full message in the internal `message` attribute. + This contains the full message in the internal + [`message`][hikari.events.message_events.GuildMessageCreateEvent.message] attribute. """ message: messages.Message = attrs.field() @@ -248,7 +250,7 @@ class DMMessageCreateEvent(MessageCreateEvent): class MessageUpdateEvent(MessageEvent, abc.ABC): """Event that is fired when a message is updated. - .. note:: + !!! note Less information will be available here than in the creation event due to Discord limitations. """ @@ -264,7 +266,7 @@ def app(self) -> traits.RESTAware: def author(self) -> undefined.UndefinedOr[users.User]: """User that sent the message. - This will be `hikari.undefined.UNDEFINED` in some cases such as when Discord + This will be [`hikari.undefined.UNDEFINED`][] in some cases such as when Discord updates a message with an embed URL preview. """ return self.message.author @@ -273,7 +275,7 @@ def author(self) -> undefined.UndefinedOr[users.User]: def author_id(self) -> undefined.UndefinedOr[snowflakes.Snowflake]: """ID of the author that triggered this event. - This will be `hikari.undefined.UNDEFINED` in some cases such as when Discord + This will be [`hikari.undefined.UNDEFINED`][] in some cases such as when Discord updates a message with an embed URL preview. """ author = self.message.author @@ -288,11 +290,11 @@ def channel_id(self) -> snowflakes.Snowflake: def content(self) -> undefined.UndefinedNoneOr[str]: """Content of the message. - The content of the message, if present. This may be `None` + The content of the message, if present. This may be [`None`][] if no content is present (e.g. if only an embed was sent). If not part of the update, then this will be - `hikari.undefined.UNDEFINED` instead. + [`hikari.undefined.UNDEFINED`][] instead. """ return self.message.content @@ -301,7 +303,7 @@ def embeds(self) -> undefined.UndefinedOr[typing.Sequence[embeds_.Embed]]: """Sequence of embeds in the message. If the embeds were not changed in this event, then this may instead be - `hikari.undefined.UNDEFINED`. + [`hikari.undefined.UNDEFINED`][]. """ return self.message.embeds @@ -311,7 +313,7 @@ def is_bot(self) -> undefined.UndefinedOr[bool]: If the author is not known, due to the update event being caused by Discord adding an embed preview to accompany a URL, then this - will return `hikari.undefined.UNDEFINED` instead. + will return [`hikari.undefined.UNDEFINED`][] instead. """ if (author := self.message.author) is not undefined.UNDEFINED: return author.is_bot @@ -324,7 +326,7 @@ def is_human(self) -> undefined.UndefinedOr[bool]: If the author is not known, due to the update event being caused by Discord adding an embed preview to accompany a URL, then this - may return `hikari.undefined.UNDEFINED` instead. + may return [`hikari.undefined.UNDEFINED`][] instead. """ # Not second-guessing some weird edge case will occur in the future with this, # so I am being safe rather than sorry. @@ -342,7 +344,7 @@ def is_webhook(self) -> undefined.UndefinedOr[bool]: If the author is not known, due to the update event being caused by Discord adding an embed preview to accompany a URL, then this - may return `hikari.undefined.UNDEFINED` instead. + may return [`hikari.undefined.UNDEFINED`][] instead. """ if (webhook_id := self.message.webhook_id) is not undefined.UNDEFINED: return webhook_id is not None @@ -366,7 +368,7 @@ def message_id(self) -> snowflakes.Snowflake: class GuildMessageUpdateEvent(MessageUpdateEvent): """Event that is fired when a message is updated in a guild. - .. note:: + !!! note Less information will be available here than in the creation event due to Discord limitations. """ @@ -374,7 +376,7 @@ class GuildMessageUpdateEvent(MessageUpdateEvent): old_message: typing.Optional[messages.PartialMessage] = attrs.field() """The old message object. - This will be `None` if the message missing from the cache. + This will be [`None`][] if the message missing from the cache. """ message: messages.PartialMessage = attrs.field() @@ -387,9 +389,9 @@ class GuildMessageUpdateEvent(MessageUpdateEvent): def member(self) -> undefined.UndefinedNoneOr[guilds.Member]: """Member that sent the message if provided by the event. - If the message is not in a guild, this will be `None`. + If the message is not in a guild, this will be [`None`][]. - This will also be `hikari.undefined.UNDEFINED` in some cases such as when Discord + This will also be [`hikari.undefined.UNDEFINED`][] in some cases such as when Discord updates a message with an embed URL preview. """ return self.message.member @@ -422,7 +424,7 @@ def get_channel(self) -> typing.Optional[channels.TextableGuildChannel]: ------- typing.Optional[hikari.channels.TextableGuildChannel] The channel that the message was sent in, if known and cached, - otherwise, `None`. + otherwise, [`None`][]. """ if not isinstance(self.app, traits.CacheAware): return None @@ -436,15 +438,15 @@ def get_channel(self) -> typing.Optional[channels.TextableGuildChannel]: def get_guild(self) -> typing.Optional[guilds.GatewayGuild]: """Get the cached guild that this event occurred in, if known. - .. note:: - This will require the `GUILDS` intent to be specified on start-up + !!! note + This will require the [`hikari.intents.Intents.GUILDS`][] intent to be specified on start-up in order to be known. Returns ------- typing.Optional[hikari.guilds.GatewayGuild] The guild that this event occurred in, if cached. Otherwise, - `None` instead. + [`None`][] instead. """ if not isinstance(self.app, traits.CacheAware): return None @@ -458,7 +460,7 @@ def get_guild(self) -> typing.Optional[guilds.GatewayGuild]: class DMMessageUpdateEvent(MessageUpdateEvent): """Event that is fired when a message is updated in a DM. - .. note:: + !!! note Less information will be available here than in the creation event due to Discord limitations. """ @@ -466,7 +468,7 @@ class DMMessageUpdateEvent(MessageUpdateEvent): old_message: typing.Optional[messages.PartialMessage] = attrs.field() """The old message object. - This will be `None` if the message missing from the cache. + This will be [`None`][] if the message missing from the cache. """ message: messages.PartialMessage = attrs.field() @@ -480,7 +482,7 @@ class DMMessageUpdateEvent(MessageUpdateEvent): class MessageDeleteEvent(MessageEvent, abc.ABC): """Special event that is triggered when a message gets deleted. - .. note:: + !!! note Due to Discord limitations, most message information is unavailable during deletion events. """ @@ -497,7 +499,7 @@ def message_id(self) -> snowflakes.Snowflake: def old_message(self) -> typing.Optional[messages.Message]: """Object of the message that was deleted. - Will be `None` if the message was not found in the cache. + Will be [`None`][] if the message was not found in the cache. """ @@ -507,7 +509,7 @@ def old_message(self) -> typing.Optional[messages.Message]: class GuildMessageDeleteEvent(MessageDeleteEvent): """Event that is triggered if a message is deleted in a guild. - .. note:: + !!! note Due to Discord limitations, most message information is unavailable during deletion events. """ @@ -536,7 +538,7 @@ def get_channel(self) -> typing.Optional[channels.TextableGuildChannel]: Returns ------- typing.Optional[hikari.channels.TextableGuildChannel] - The channel the messages were sent in, or `None` if not + The channel the messages were sent in, or [`None`][] if not known/cached. """ if not isinstance(self.app, traits.CacheAware): @@ -551,8 +553,8 @@ def get_channel(self) -> typing.Optional[channels.TextableGuildChannel]: def get_guild(self) -> typing.Optional[guilds.GatewayGuild]: """Get the cached guild this event corresponds to, if known. - .. note:: - You will need `hikari.intents.Intents.GUILDS` enabled to receive this + !!! note + You will need [`hikari.intents.Intents.GUILDS`][] enabled to receive this information. Returns @@ -573,7 +575,7 @@ def get_guild(self) -> typing.Optional[guilds.GatewayGuild]: class DMMessageDeleteEvent(MessageDeleteEvent): """Event that is triggered if a message is deleted in a DM. - .. note:: + !!! note Due to Discord limitations, most message information is unavailable during deletion events. """ @@ -600,7 +602,7 @@ class DMMessageDeleteEvent(MessageDeleteEvent): class GuildBulkMessageDeleteEvent(shard_events.ShardEvent): """Event that is triggered when a bulk deletion is triggered in a guild. - .. note:: + !!! note Due to Discord limitations, most message information is unavailable during deletion events. """ @@ -632,7 +634,7 @@ def get_channel(self) -> typing.Optional[channels.TextableGuildChannel]: Returns ------- typing.Optional[hikari.channels.TextableGuildChannel] - The channel the messages were sent in, or `None` if not + The channel the messages were sent in, or [`None`][] if not known/cached. """ if not isinstance(self.app, traits.CacheAware): @@ -647,8 +649,8 @@ def get_channel(self) -> typing.Optional[channels.TextableGuildChannel]: def get_guild(self) -> typing.Optional[guilds.GatewayGuild]: """Get the cached guild this event corresponds to, if known. - .. note:: - You will need `hikari.intents.Intents.GUILDS` enabled to receive this + !!! note + You will need [`hikari.intents.Intents.GUILDS`][] enabled to receive this information. Returns diff --git a/hikari/events/reaction_events.py b/hikari/events/reaction_events.py index 60b98f20b5..7cb631c09a 100644 --- a/hikari/events/reaction_events.py +++ b/hikari/events/reaction_events.py @@ -113,15 +113,15 @@ def emoji_name(self) -> typing.Union[emojis.UnicodeEmoji, str, None]: """Name of the emoji which was added if known. This can either be the string name of the custom emoji which was added, - the object of the `hikari.emojis.UnicodeEmoji` which was added or - `None` when the relevant custom emoji's data is not available + the object of the [`hikari.emojis.UnicodeEmoji`][] which was added or + [`None`][] when the relevant custom emoji's data is not available (e.g. the emoji has been deleted). """ @property @abc.abstractmethod def emoji_id(self) -> typing.Optional[snowflakes.Snowflake]: - """ID of the emoji which was added if it is custom, else `None`.""" + """ID of the emoji which was added if it is custom, else [`None`][].""" @property @abc.abstractmethod @@ -136,7 +136,7 @@ def is_for_emoji(self, emoji: typing.Union[emojis.Emoji, str], /) -> bool: emoji : typing.Union[hikari.emojis.Emoji, str] The emoji to check. - Passing `str` here indicates a unicode emoji. + Passing [`str`][] here indicates a unicode emoji. Returns ------- @@ -163,7 +163,7 @@ def emoji_name(self) -> typing.Union[emojis.UnicodeEmoji, str, None]: """Name of the emoji which was removed. Either the string name of the custom emoji which was removed, the object - of the `hikari.emojis.UnicodeEmoji` which was removed or `None` + of the [`hikari.emojis.UnicodeEmoji`][] which was removed or [`None`][] when the relevant custom emoji's data is not available (e.g. the emoji has been deleted). """ @@ -171,7 +171,7 @@ def emoji_name(self) -> typing.Union[emojis.UnicodeEmoji, str, None]: @property @abc.abstractmethod def emoji_id(self) -> typing.Optional[snowflakes.Snowflake]: - """ID of the emoji which was added if it is custom, else `None`.""" + """ID of the emoji which was added if it is custom, else [`None`][].""" def is_for_emoji(self, emoji: typing.Union[emojis.Emoji, str], /) -> bool: """Get whether the reaction event is for a specific emoji. @@ -181,7 +181,7 @@ def is_for_emoji(self, emoji: typing.Union[emojis.Emoji, str], /) -> bool: emoji : typing.Union[hikari.emojis.Emoji, str] The emoji to check. - Passing `str` here indicates a unicode emoji. + Passing [`str`][] here indicates a unicode emoji. Returns ------- @@ -210,7 +210,7 @@ def emoji_name(self) -> typing.Union[emojis.UnicodeEmoji, str, None]: """Name of the emoji which was removed. Either the string name of the custom emoji which was removed, the object - of the `hikari.emojis.UnicodeEmoji` which was removed or `None` + of the [`hikari.emojis.UnicodeEmoji`][] which was removed or [`None`][] when the relevant custom emoji's data is not available (e.g. the emoji has been deleted). """ @@ -218,7 +218,7 @@ def emoji_name(self) -> typing.Union[emojis.UnicodeEmoji, str, None]: @property @abc.abstractmethod def emoji_id(self) -> typing.Optional[snowflakes.Snowflake]: - """ID of the emoji which was added if it is custom, else `None`.""" + """ID of the emoji which was added if it is custom, else [`None`][].""" def is_for_emoji(self, emoji: typing.Union[emojis.Emoji, str], /) -> bool: """Get whether the reaction event is for a specific emoji. @@ -228,7 +228,7 @@ def is_for_emoji(self, emoji: typing.Union[emojis.Emoji, str], /) -> bool: emoji : typing.Union[hikari.emojis.Emoji, str] The emoji to check. - Passing `str` here indicates a unicode emoji. + Passing [`str`][] here indicates a unicode emoji. Returns ------- diff --git a/hikari/events/role_events.py b/hikari/events/role_events.py index 7164b89e05..298b38456c 100644 --- a/hikari/events/role_events.py +++ b/hikari/events/role_events.py @@ -99,7 +99,7 @@ class RoleUpdateEvent(RoleEvent): old_role: typing.Optional[guilds.Role] = attrs.field() """The old role object. - This will be `None` if the role missing from the cache. + This will be [`None`][] if the role missing from the cache. """ role: guilds.Role = attrs.field() @@ -142,5 +142,5 @@ class RoleDeleteEvent(RoleEvent): old_role: typing.Optional[guilds.Role] = attrs.field() """The old role object. - This will be `None` if the role was missing from the cache. + This will be [`None`][] if the role was missing from the cache. """ diff --git a/hikari/events/shard_events.py b/hikari/events/shard_events.py index b6ea39b3b9..5dd22a8372 100644 --- a/hikari/events/shard_events.py +++ b/hikari/events/shard_events.py @@ -70,9 +70,9 @@ def shard(self) -> gateway_shard.GatewayShard: class ShardPayloadEvent(ShardEvent): """Event fired for most shard events with their raw payload. - .. note:: + !!! note This will only be dispatched for real dispatch events received from - Discord and not artificial events like the `ShardStateEvent` events. + Discord and not artificial events like the [`hikari.events.shard_events.ShardStateEvent`][] events. """ app: traits.RESTAware = attrs.field(metadata={attrs_extensions.SKIP_DEEP_COPY: True}) @@ -205,14 +205,15 @@ class MemberChunkEvent(ShardEvent, typing.Sequence["guilds.Member"]): presences: typing.Mapping[snowflakes.Snowflake, presences_.MemberPresence] = attrs.field(repr=False) """Mapping of user IDs to found member presence objects. - This will be empty if no presences are found or `include_presences` is not passed as - `True` while requesting the member chunks. + This will be empty if no presences are found or + [`include_presences`][hikari.api.shard.GatewayShard.request_guild_members] is + not passed as [`True`][] while requesting the member chunks. """ nonce: typing.Optional[str] = attrs.field(repr=True) """String nonce used to identify the request member chunks are associated with. - This is the nonce value passed while requesting member chunks or `None` + This is the nonce value passed while requesting member chunks or [`None`][] if there was no nonce passed. """ diff --git a/hikari/events/typing_events.py b/hikari/events/typing_events.py index c1d634505d..6d00ec7f4e 100644 --- a/hikari/events/typing_events.py +++ b/hikari/events/typing_events.py @@ -222,12 +222,12 @@ def get_channel(self) -> typing.Optional[channels.TextableGuildChannel]: def get_guild(self) -> typing.Optional[guilds.GatewayGuild]: """Get the cached object of the guild this typing event occurred in. - If the guild is not found then this will return `None`. + If the guild is not found then this will return [`None`][]. Returns ------- typing.Optional[hikari.guilds.GatewayGuild] - The object of the gateway guild if found else `None`. + The object of the gateway guild if found else [`None`][]. """ if not isinstance(self.app, traits.CacheAware): return None @@ -269,7 +269,7 @@ async def fetch_channel(self) -> channels.DMChannel: hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError diff --git a/hikari/events/user_events.py b/hikari/events/user_events.py index 6250147f3e..2167da4259 100644 --- a/hikari/events/user_events.py +++ b/hikari/events/user_events.py @@ -49,7 +49,7 @@ class OwnUserUpdateEvent(shard_events.ShardEvent): old_user: typing.Optional[users.OwnUser] = attrs.field() """The old application user. - This will be `None` if the user missing from the cache. + This will be [`None`][] if the user missing from the cache. """ user: users.OwnUser = attrs.field() diff --git a/hikari/events/voice_events.py b/hikari/events/voice_events.py index dbe05d5684..853baf13d3 100644 --- a/hikari/events/voice_events.py +++ b/hikari/events/voice_events.py @@ -72,7 +72,7 @@ class VoiceStateUpdateEvent(VoiceEvent): old_state: typing.Optional[voices.VoiceState] = attrs.field(repr=True) """The old voice state. - This will be `None` if the voice state missing from the cache. + This will be [`None`][] if the voice state missing from the cache. """ state: voices.VoiceState = attrs.field(repr=True) @@ -113,20 +113,21 @@ class VoiceServerUpdateEvent(VoiceEvent): raw_endpoint: typing.Optional[str] = attrs.field(repr=True) """Raw endpoint URI that Discord sent. - If this is `None`, it means that the server has been deallocated + If this is [`None`][], it means that the server has been deallocated and you have to disconnect. You will later receive a new event specifying what endpoint to connect to. - .. warning:: - This will not contain the scheme to use. Use the `endpoint` property - to get a representation that has this prepended. + !!! warning + This will not contain the scheme to use. Use the + [`endpoint`][hikari.events.voice_events.VoiceServerUpdateEvent.endpoint] + property to get a representation that has this prepended. """ @property def endpoint(self) -> typing.Optional[str]: """URI for this voice server host, with the correct scheme prepended. - If this is `None`, it means that the server has been deallocated + If this is [`None`][], it means that the server has been deallocated and you have to disconnect. You will later receive a new event specifying what endpoint to connect to. """ diff --git a/hikari/files.py b/hikari/files.py index 46e1f0cf44..8d90f6abd0 100644 --- a/hikari/files.py +++ b/hikari/files.py @@ -78,8 +78,8 @@ This may be one of: -- `str` path. -- `os.PathLike` derivative, such as `pathlib.PurePath` and `pathlib.Path`. +- [`str`][] path. +- [`os.PathLike`][] derivative, such as [`pathlib.PurePath`][] and [`pathlib.Path`][]. """ RAWISH_TYPES = (bytes, bytearray, memoryview, io.BytesIO, io.StringIO) @@ -89,11 +89,11 @@ This may be one of: -- `bytes` -- `bytearray` -- `memoryview` -- `io.BytesIO` -- `io.StringIO` (assuming UTF-8 encoding). +- [`bytes`][] +- [`bytearray`][] +- [`memoryview`][] +- [`io.BytesIO`][] +- [`io.StringIO`][] (assuming UTF-8 encoding). """ LazyByteIteratorish = typing.Union[ @@ -116,16 +116,16 @@ This may be one of: -- `typing.AsyncIterator[bytes]` -- `typing.AsyncIterable[bytes]` -- `typing.Iterator[bytes]` -- `typing.Iterable[bytes]` -- `typing.AsyncIterator[str]` (assuming UTF-8 encoding). -- `typing.AsyncIterable[str]` (assuming UTF-8 encoding). -- `typing.Iterator[str]` (assuming UTF-8 encoding). -- `typing.Iterable[str]` (assuming UTF-8 encoding). -- `asyncio.StreamReader` -- `aiohttp.StreamReader` +- [`typing.AsyncIterator`][][[`bytes`][]] +- [`typing.AsyncIterable`][][[`bytes`][]] +- [`typing.Iterator`][][[`bytes`][]] +- [`typing.Iterator`][][[`bytes`][]] +- [`typing.AsyncIterator`][][[`str`][]] (assuming UTF-8 encoding). +- [`typing.AsyncIterable`][][[`str`][]] (assuming UTF-8 encoding). +- [`typing.Iterator`][][[`str`][]] (assuming UTF-8 encoding). +- [`typing.Iterable`][][[`str`][]] (assuming UTF-8 encoding). +- [`asyncio.StreamReader`][] +- [`aiohttp.StreamReader`][] """ Resourceish = typing.Union["Resource[typing.Any]", Pathish, Rawish] @@ -133,19 +133,19 @@ This may be one of: -- `Resource` or a derivative. -- `str` path. -- `os.PathLike` derivative, such as `pathlib.PurePath` and `pathlib.Path`. -- `bytes` -- `bytearray` -- `memoryview` -- `io.BytesIO` -- `io.StringIO` (assuming UTF-8 encoding). +- [`hikari.files.Resource`][] or a derivative. +- [`str`][] path. +- [`os.PathLike`][] derivative, such as [`pathlib.PurePath`][] and [`pathlib.Path`][]. +- [`bytes`][] +- [`bytearray`][] +- [`memoryview`][] +- [`io.BytesIO`][] +- [`io.StringIO`][] (assuming UTF-8 encoding). """ def ensure_path(pathish: Pathish) -> pathlib.Path: - """Convert a path-like object to a `pathlib.Path` instance.""" + """Convert a path-like object to a [`pathlib.Path`][] instance.""" return pathlib.Path(pathish) @@ -169,8 +169,8 @@ def ensure_resource(url_or_resource: Resourceish, /) -> Resource[AsyncReader]: Parameters ---------- url_or_resource : Resourceish - The item to convert. If a `Resource` is passed, it is - simply returned again. Anything else is converted to a `Resource` first. + The item to convert. If a [`hikari.files.Resource`][] is passed, it is + simply returned again. Anything else is converted to a [`hikari.files.Resource`][] first. Returns ------- @@ -211,7 +211,7 @@ def guess_mimetype_from_filename(name: str, /) -> typing.Optional[str]: Returns ------- typing.Optional[str] - The closest guess to the given filename. May be `None` if + The closest guess to the given filename. May be [`None`][] if no match was found. """ guess, _ = mimetypes.guess_type(name) @@ -221,7 +221,7 @@ def guess_mimetype_from_filename(name: str, /) -> typing.Optional[str]: def guess_mimetype_from_data(data: bytes, /) -> typing.Optional[str]: """Guess the mimetype of some data from the header. - .. warning:: + !!! warning This function only detects valid image headers that Discord allows the use of. Anything else will go undetected. @@ -234,7 +234,7 @@ def guess_mimetype_from_data(data: bytes, /) -> typing.Optional[str]: ------- typing.Optional[str] The mimetype, if it was found. If the header is unrecognised, then - `None` is returned. + [`None`][] is returned. """ if data.startswith(b"\211PNG\r\n\032\n"): return "image/png" @@ -257,16 +257,16 @@ def guess_file_extension(mimetype: str) -> typing.Optional[str]: Examples -------- - .. code-block:: python - + ```py >>> guess_file_extension("image/png") ".png" + ``` Returns ------- typing.Optional[str] - The file extension, prepended with a ``.``. If no match was found, - return `None`. + The file extension, prepended with a `.`. If no match was found, + return [`None`][]. """ return mimetypes.guess_extension(mimetype) @@ -282,11 +282,11 @@ def generate_filename_from_details( Parameters ---------- mimetype : typing.Optional[str] - The mimetype of the content, or `None` if not known. + The mimetype of the content, or [`None`][] if not known. extension : typing.Optional[str] - The file extension to use, or `None` if not known. + The file extension to use, or [`None`][] if not known. data : typing.Optional[bytes] - The data to inspect, or `None` if not known. + The data to inspect, or [`None`][] if not known. Returns ------- @@ -316,7 +316,7 @@ def to_data_uri(data: bytes, mimetype: typing.Optional[str]) -> str: data : bytes The data to encode as base64. mimetype : typing.Optional[str] - The mimetype, or `None` if we should attempt to guess it. + The mimetype, or [`None`][] if we should attempt to guess it. Returns ------- @@ -345,7 +345,7 @@ class AsyncReader(typing.AsyncIterable[bytes], abc.ABC): """The filename of the resource.""" mimetype: typing.Optional[str] = attrs.field(repr=True) - """The mimetype of the resource. May be `None` if not known.""" + """The mimetype of the resource. May be [`None`][] if not known.""" async def data_uri(self) -> str: """Fetch the data URI. @@ -355,7 +355,7 @@ async def data_uri(self) -> str: return to_data_uri(await self.read(), self.mimetype) async def read(self) -> bytes: - """Read the rest of the resource and return it in a `bytes` object.""" + """Read the rest of the resource and return it in a [`bytes`][] object.""" buff = bytearray() async for chunk in self: buff.extend(chunk) @@ -413,7 +413,7 @@ def _to_write_path(path: Pathish, default_filename: str, force: bool) -> pathlib path = path.joinpath(default_filename) if not force and path.exists(): - raise FileExistsError(f"file {path!r} already exists; use `force=True` to overwrite") + raise FileExistsError(f"file {path!r} already exists; use [force=True][] to overwrite") return path.expanduser() @@ -452,14 +452,14 @@ def extension(self) -> typing.Optional[str]: async def read(self, *, executor: typing.Optional[concurrent.futures.Executor] = None) -> bytes: """Read the entire resource at once into memory. - .. code-block:: python - + ```py data = await resource.read(...) # ^-- This is a shortcut for the following --v async with resource.stream(...) as reader: data = await reader.read() + ``` - .. warning:: + !!! warning If you simply wish to re-upload this resource to Discord via any endpoint in Hikari, you should opt to just pass this resource object directly. This way, Hikari can perform byte @@ -470,7 +470,7 @@ async def read(self, *, executor: typing.Optional[concurrent.futures.Executor] = ---------- executor : typing.Optional[concurrent.futures.Executor] The executor to run in for blocking operations. - If `None`, then the default executor is used for the + If [`None`][], then the default executor is used for the current event loop. Returns @@ -496,10 +496,10 @@ async def save( path will be relative to the current working directory. executor : typing.Optional[concurrent.futures.Executor] The executor to run in for blocking operations. - If `None`, then the default executor is used for + If [`None`][], then the default executor is used for the current event loop. force : bool - Whether to overwrite an existing file. Defaults to `False`. + Whether to overwrite an existing file. """ loop = asyncio.get_running_loop() file = await loop.run_in_executor(executor, _open_write_path, path, self.filename, force) @@ -521,15 +521,13 @@ def stream( ---------- executor : typing.Optional[concurrent.futures.Executor] The executor to run in for blocking operations. - If `None`, then the default executor is used for the + If [`None`][], then the default executor is used for the current event loop. head_only : bool - Defaults to `False`. If `True`, then the - implementation may only retrieve HEAD information if supported. - This currently only has any effect for web requests. This will - fetch the headers for the HTTP resource this object points to - without downloading the entire content, which can be significantly - faster if you are scanning file types in messages, for example. + If [`True`][], then only the headers for the HTTP resource this + object points to will be fetched without downloading the entire + content, which can be significantly faster if you are scanning + file types in messages, for example. Returns ------- @@ -564,7 +562,7 @@ class WebReader(AsyncReader): """Asynchronous reader to use to read data from a web resource.""" stream: aiohttp.StreamReader = attrs.field(repr=False) - """The `aiohttp.StreamReader` to read the content from.""" + """The [`aiohttp.StreamReader`][] to read the content from.""" url: str = attrs.field(repr=False) """The URL being read from.""" @@ -582,10 +580,10 @@ class WebReader(AsyncReader): """The size of the resource, if known.""" head_only: bool = attrs.field() - """If `True`, then only the HEAD was requested. + """If [`True`][], then only the HEAD was requested. - In this case, neither `__aiter__` nor `read` would return anything other - than an empty byte string. + In this case, reading data off the object will return an empty + byte string """ async def read(self) -> bytes: @@ -668,12 +666,12 @@ class WebResource(Resource[WebReader], abc.ABC): The logic for identifying this resource is left to each implementation to define. - For a usable concrete implementation, use `URL` instead. + For a usable concrete implementation, use [`hikari.files.URL`][] instead. Some components may choose to not upload this resource directly and instead simply refer to the URL as needed. The main place this will occur is within embeds. If you need to re-upload the resource, you - should download it into a `bytes` and pass that instead in these cases. + should download it into a [`bytes`][] and pass that instead in these cases. """ __slots__: typing.Sequence[str] = () @@ -691,23 +689,22 @@ def stream( executor : typing.Optional[concurrent.futures.Executor] Not used. Provided only to match the underlying interface. head_only : bool - Defaults to `False`. If `True`, then the - implementation may only retrieve HEAD information if supported. - This currently only has any effect for web requests. + If [`True`][], then the implementation may only retrieve HEAD + information if supported. This currently only has any + effect for web requests. Examples -------- Downloading an entire resource at once into memory: - .. code-block:: python - + ```py async with obj.stream() as stream: data = await stream.read() + ``` Checking the metadata: - .. code-block:: python - + ```py async with obj.stream() as stream: mimetype = stream.mimetype @@ -717,13 +714,14 @@ def stream( ... else: ... + ``` Fetching the data-uri of a resource: - .. code-block:: python - + ```py async with obj.stream() as stream: data_uri = await stream.data_uri() + ``` Returns ------- @@ -755,13 +753,13 @@ def stream( class URL(WebResource): """A URL that represents a web resource. - .. note:: + !!! note Some components may choose to not upload this resource directly and instead simply refer to the URL as needed. The main place this will occur is within embeds. If you need to re-upload the resource, you should download it into - a `bytes` and pass that instead in these cases. + a [`bytes`][] and pass that instead in these cases. Parameters ---------- @@ -867,17 +865,17 @@ class File(Resource[ThreadedFileReader]): path : typing.Union[str, os.PathLike, pathlib.Path] The path to use. - If passing a `pathlib.Path`, this must not be a `pathlib.PurePath` + If passing a [`pathlib.Path`][], this must not be a [`pathlib.PurePath`][] directly, as it will be used to expand tokens such as `~` that denote the home directory, and `..` for relative paths. This will all be performed as required in an executor to prevent blocking the event loop. filename : typing.Optional[str] - The filename to use. If this is `None`, the name of the file is taken + The filename to use. If this is [`None`][], the name of the file is taken from the path instead. spoiler : bool - Whether to mark the file as a spoiler in Discord. Defaults to `False`. + Whether to mark the file as a spoiler in Discord. """ __slots__: typing.Sequence[str] = ("path", "_filename", "is_spoiler") @@ -918,10 +916,10 @@ def stream( ---------- executor : typing.Optional[concurrent.futures.Executor] The thread executor to run the blocking read operations in. If - `None`, the default executor for the running event loop + [`None`][], the default executor for the running event loop will be used instead. - Only `concurrent.futures.TheadPoolExecutor` is supported. + Only [`concurrent.futures.ThreadPoolExecutor`][] is supported. head_only : bool Not used. Provided only to match the underlying interface. @@ -1048,11 +1046,11 @@ class Bytes(Resource[IteratorReader]): filename : str The filename to use. mimetype : typing.Optional[str] - The mimetype, or `None` if you do not wish to specify this. + The mimetype, or [`None`][] if you do not wish to specify this. If not provided, then this will be generated from the file extension of the filename instead. spoiler : bool - Whether to mark the file as a spoiler in Discord. Defaults to `False`. + Whether to mark the file as a spoiler in Discord. """ __slots__: typing.Sequence[str] = ("data", "_filename", "mimetype", "is_spoiler") @@ -1061,7 +1059,7 @@ class Bytes(Resource[IteratorReader]): """The raw data/provider of raw data to upload.""" mimetype: typing.Optional[str] - """The provided mimetype, if provided. Otherwise `None`.""" + """The provided mimetype, if provided. Otherwise [`None`][].""" is_spoiler: bool """Whether the file will be marked as a spoiler.""" @@ -1145,7 +1143,7 @@ def from_data_uri(data_uri: str, filename: typing.Optional[str] = None) -> Bytes Returns ------- Bytes - The parsed data URI as a `Bytes` object. + The parsed data URI as a [`hikari.files.Bytes`][] object. Raises ------ diff --git a/hikari/guilds.py b/hikari/guilds.py index c76ca24a83..6f47e3e009 100644 --- a/hikari/guilds.py +++ b/hikari/guilds.py @@ -305,7 +305,7 @@ class GuildWidget: async def fetch_channel(self) -> typing.Optional[channels_.GuildChannel]: """Fetch the widget channel. - This will be `None` if not set. + This will be [`None`][] if not set. Returns ------- @@ -313,14 +313,14 @@ async def fetch_channel(self) -> typing.Optional[channels_.GuildChannel]: The requested channel. You can check the type of the channel by - using `isinstance`. + using [`isinstance`][]. Raises ------ hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -347,51 +347,51 @@ class Member(users.User): """The ID of the guild this member belongs to.""" is_deaf: undefined.UndefinedOr[bool] = attrs.field(repr=False) - """`True` if this member is deafened in the current voice channel. + """[`True`][] if this member is deafened in the current voice channel. - This will be `hikari.undefined.UNDEFINED` if it's state is + This will be [`hikari.undefined.UNDEFINED`][] if it's state is unknown. """ is_mute: undefined.UndefinedOr[bool] = attrs.field(repr=False) - """`True` if this member is muted in the current voice channel. + """[`True`][] if this member is muted in the current voice channel. - This will be `hikari.undefined.UNDEFINED` if it's state is unknown. + This will be [`hikari.undefined.UNDEFINED`][] if it's state is unknown. """ is_pending: undefined.UndefinedOr[bool] = attrs.field(repr=False) """Whether the user has passed the guild's membership screening requirements. - This will be `hikari.undefined.UNDEFINED` if it's state is unknown. + This will be [`hikari.undefined.UNDEFINED`][] if it's state is unknown. """ joined_at: typing.Optional[datetime.datetime] = attrs.field(repr=True) """The datetime of when this member joined the guild they belong to. - This will be `None` for guest members that have been temporarily + This will be [`None`][] for guest members that have been temporarily invited. """ nickname: typing.Optional[str] = attrs.field(repr=True) """This member's nickname. - This will be `None` if not set. + This will be [`None`][] if not set. """ premium_since: typing.Optional[datetime.datetime] = attrs.field(repr=False) """The datetime of when this member started "boosting" this guild. - Will be `None` if the member is not a premium user. + Will be [`None`][] if the member is not a premium user. """ raw_communication_disabled_until: typing.Optional[datetime.datetime] = attrs.field(repr=False) """The datetime when this member's timeout will expire. - Will be `None` if the member is not timed out. + Will be [`None`][] if the member is not timed out. - .. note:: + !!! note The datetime might be in the past, so it is recommended to use - `communication_disabled_until` method to check if the member is timed + [`hikari.guilds.Member.communication_disabled_until`][] method to check if the member is timed out at the time of the call. """ @@ -408,10 +408,10 @@ class Member(users.User): """This member's corresponding user object.""" guild_avatar_hash: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) - """Hash of the member's guild avatar guild if set, else `None`. + """Hash of the member's guild avatar guild if set, else [`None`][]. - .. note:: - This takes precedence over `Member.avatar_hash`. + !!! note + This takes precedence over [`hikari.guilds.Member.avatar_hash`][]. """ @property @@ -431,8 +431,8 @@ def avatar_url(self) -> typing.Optional[files.URL]: def guild_avatar_url(self) -> typing.Optional[files.URL]: """Guild Avatar URL for the user, if they have one set. - May be `None` if no guild avatar is set. In this case, you - should use `avatar_hash` or `default_avatar_url` instead. + May be [`None`][] if no guild avatar is set. In this case, you + should use [`hikari.guilds.Member.avatar_hash`][] or [`hikari.guilds.Member.default_avatar_url`][] instead. """ return self.make_guild_avatar_url() @@ -470,9 +470,9 @@ def display_name(self) -> str: See Also -------- - Nickname: `Member.nickname`. - Username: `Member.username`. - Globalname: `Member.global_name`. + Nickname: [`Member.nickname`][]. + Username: [`Member.username`][]. + Globalname: [`Member.global_name`][]. """ return self.nickname or self.global_name or self.username @@ -500,9 +500,9 @@ def communication_disabled_until(self) -> typing.Optional[datetime.datetime]: """Return when the timeout for this member ends. Unlike `raw_communication_disabled_until`, this will always be - `None` if the member is not currently timed out. + [`None`][] if the member is not currently timed out. - .. note:: + !!! note The output of this function can depend based on when the function is called. """ @@ -519,7 +519,7 @@ def get_guild(self) -> typing.Optional[Guild]: Returns ------- typing.Optional[hikari.guilds.Guild] - The linked guild object or `None` if it's not cached. + The linked guild object or [`None`][] if it's not cached. """ if not isinstance(self.user.app, traits.CacheAware): return None @@ -531,12 +531,12 @@ def get_presence(self) -> typing.Optional[presences_.MemberPresence]: Presence info includes user status and activities. - This requires the `GUILD_PRESENCES` intent to be enabled. + This requires the [`hikari.intents.Intents.GUILD_PRESENCES`][] intent to be enabled. Returns ------- typing.Optional[hikari.presences.MemberPresence] - The member presence, or `None` if not known. + The member presence, or [`None`][] if not known. """ if not isinstance(self.user.app, traits.CacheAware): return None @@ -570,7 +570,7 @@ def get_top_role(self) -> typing.Optional[Role]: Returns ------- typing.Optional[hikari.guilds.Role] - `None` if the cache is missing the roles information or + [`None`][] if the cache is missing the roles information or the highest role the user has. """ roles = sorted(self.get_roles(), key=lambda r: r.position, reverse=True) @@ -596,29 +596,28 @@ def make_guild_avatar_url( ) -> typing.Optional[files.URL]: """Generate the guild specific avatar url for this member, if set. - If no guild avatar is set, this returns `None`. You can then - use the `make_avatar_url` to get their global custom avatar or - `default_avatar_url` if they have no custom avatar set. + If no guild avatar is set, this returns [`None`][]. Parameters ---------- ext : typing.Optional[str] - The ext to use for this URL, defaults to `png` or `gif`. + The ext to use for this URL. Supports `png`, `jpeg`, `jpg`, `webp` and `gif` (when - animated). Will be ignored for default avatars which can only be - `png`. + animated). + + Will be ignored for default avatars which can only be `png`. - If `None`, then the correct default extension is + 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. + The size to set for the URL. + 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. + The URL to the avatar, or [`None`][] if not present. Raises ------ @@ -704,7 +703,7 @@ async def ban( delete_message_seconds : hikari.undefined.UndefinedNoneOr[hikari.internal.time.Intervalish] If provided, the number of seconds to delete messages for. This can be represented as either an int/float between 0 and 604800 (7 days), or - a `datetime.timedelta` object. + a [`datetime.timedelta`][] object. reason : hikari.undefined.UndefinedOr[str] If provided, the reason that will be recorded in the audit logs. Maximum of 512 characters. @@ -714,7 +713,7 @@ async def ban( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `BAN_MEMBERS` permission. + If you are missing the [`hikari.permissions.Permissions.BAN_MEMBERS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -743,7 +742,7 @@ async def unban(self, *, reason: undefined.UndefinedOr[str] = undefined.UNDEFINE hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `BAN_MEMBERS` permission. + If you are missing the [`hikari.permissions.Permissions.BAN_MEMBERS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -770,7 +769,7 @@ async def kick(self, *, reason: undefined.UndefinedOr[str] = undefined.UNDEFINED hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `KICK_MEMBERS` permission. + If you are missing the [`hikari.permissions.Permissions.KICK_MEMBERS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -803,7 +802,7 @@ async def add_role( Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_ROLES` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_ROLES`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -836,7 +835,7 @@ async def remove_role( Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_ROLES` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_ROLES`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -867,40 +866,40 @@ async def edit( Other Parameters ---------------- nickname : hikari.undefined.UndefinedNoneOr[str] - If provided, the new nick for the member. If `None`, + If provided, the new nick for the member. If [`None`][], will remove the members nick. - Requires the `MANAGE_NICKNAMES` permission. + Requires the [`hikari.permissions.Permissions.MANAGE_NICKNAMES`][] permission. roles : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishSequence[hikari.guilds.PartialRole]] If provided, the new roles for the member. - Requires the `MANAGE_ROLES` permission. + Requires the [`hikari.permissions.Permissions.MANAGE_ROLES`][] permission. mute : hikari.undefined.UndefinedOr[bool] If provided, the new server mute state for the member. - Requires the `MUTE_MEMBERS` permission. + Requires the [`hikari.permissions.Permissions.MUTE_MEMBERS`][] permission. deaf : hikari.undefined.UndefinedOr[bool] If provided, the new server deaf state for the member. - Requires the `DEAFEN_MEMBERS` permission. + Requires the [`hikari.permissions.Permissions.DEAFEN_MEMBERS`][] permission. voice_channel : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.channels.GuildVoiceChannel]]] - If provided, `None` or the object or the ID of + If provided, [`None`][] or the object or the ID of an existing voice channel to move the member to. - If `None`, will disconnect the member from voice. + If [`None`][], will disconnect the member from voice. - Requires the `MOVE_MEMBERS` permission and the `CONNECT` - permission in the original voice channel and the target - voice channel. + Requires the [`hikari.permissions.Permissions.MOVE_MEMBERS`][] permission + and the [`hikari.permissions.Permissions.CONNECT`][] permission in the + original voice channel and the target voice channel. - .. note:: + !!! note If the member is not in a voice channel, this will take no effect. communication_disabled_until : hikari.undefined.UndefinedNoneOr[datetime.datetime] If provided, the datetime when the timeout (disable communication) - of the member expires, up to 28 days in the future, or `None` + of the member expires, up to 28 days in the future, or [`None`][] to remove the timeout from the member. - Requires the `MODERATE_MEMBERS` permission. + Requires the [`hikari.permissions.Permissions.MODERATE_MEMBERS`][] permission. reason : hikari.undefined.UndefinedOr[str] If provided, the reason that will be recorded in the audit logs. Maximum of 512 characters. @@ -989,14 +988,14 @@ class Role(PartialRole): is_hoisted: bool = attrs.field(eq=False, hash=False, repr=True) """Whether this role is hoisting the members it's attached to in the member list. - Members will be hoisted under their highest role where this is set to `True`. + Members will be hoisted under their highest role where this is set to [`True`][]. """ icon_hash: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) - """Hash of the role's icon if set, else `None`.""" + """Hash of the role's icon if set, else [`None`][].""" unicode_emoji: typing.Optional[emojis_.UnicodeEmoji] = attrs.field(eq=False, hash=False, repr=False) - """Role's icon as an unicode emoji if set, else `None`.""" + """Role's icon as an unicode emoji if set, else [`None`][].""" is_managed: bool = attrs.field(eq=False, hash=False, repr=False) """Whether this role is managed by an integration.""" @@ -1020,13 +1019,13 @@ class Role(PartialRole): bot_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=True) """The ID of the bot this role belongs to. - If `None`, this is not a bot role. + If [`None`][], this is not a bot role. """ integration_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=True) """The ID of the integration this role belongs to. - If `None`, this is not a integration role. + If [`None`][], this is not a integration role. """ is_premium_subscriber_role: bool = attrs.field(eq=False, hash=False, repr=True) @@ -1035,7 +1034,7 @@ class Role(PartialRole): subscription_listing_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=True) """The ID of this role's subscription SKU and listing. - If `None`, this is not a purchasable role. + If [`None`][], this is not a purchasable role. """ is_available_for_purchase: bool = attrs.field(eq=False, hash=False, repr=True) @@ -1059,7 +1058,7 @@ def mention(self) -> str: """Return a raw mention string for the role. When this role represents @everyone mentions will only work if - `mentions_everyone` is `True`. + `mentions_everyone` is [`True`][]. """ if self.guild_id == self.id: return "@everyone" @@ -1069,21 +1068,21 @@ def mention(self) -> str: def make_icon_url(self, *, ext: str = "png", size: int = 4096) -> typing.Optional[files.URL]: """Generate the icon URL for this role, if set. - If no role icon is set, this returns `None`. + If no role icon is set, this returns [`None`][]. Parameters ---------- ext : str - The extension to use for this URL, defaults to `png`. + The extension to use for this URL. Supports `png`, `jpeg`, `jpg` and `webp`. size : int - The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- typing.Optional[hikari.files.URL] - The URL to the icon, or `None` if not present. + The URL to the icon, or [`None`][] if not present. Raises ------ @@ -1173,16 +1172,16 @@ def make_icon_url(self, *, ext: str = "png", size: int = 4096) -> typing.Optiona Parameters ---------- ext : str - The extension to use for this URL, defaults to `png`. + The extension to use for this URL. Supports `png`, `jpeg`, `jpg` and `webp`. size : int - The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- typing.Optional[hikari.files.URL] - The URL, or `None` if no icon exists. + The URL, or [`None`][] if no icon exists. Raises ------ @@ -1241,15 +1240,15 @@ class Integration(PartialIntegration): This will not be enacted until after `GuildIntegration.expire_grace_period` passes. - .. note:: - This will always be `None` for Discord integrations. + !!! note + This will always be [`None`][] for Discord integrations. """ expire_grace_period: typing.Optional[datetime.timedelta] = attrs.field(eq=False, hash=False, repr=False) """How many days users with expired subscriptions are given until the expire behavior is enacted out on them. - .. note:: - This will always be `None` for Discord integrations. + !!! note + This will always be [`None`][] for Discord integrations. """ is_enabled: bool = attrs.field(eq=False, hash=False, repr=True) @@ -1279,7 +1278,7 @@ class Integration(PartialIntegration): application: typing.Optional[IntegrationApplication] = attrs.field(eq=False, hash=False, repr=False) """The bot/OAuth2 application associated with this integration. - .. note:: + !!! note This is only available for Discord integrations. """ @@ -1300,7 +1299,7 @@ class WelcomeChannel: ) """The emoji shown in the welcome screen channel if set to a unicode emoji. - .. warning:: + !!! warning While it may also be present for custom emojis, this is neither guaranteed to be provided nor accurate. """ @@ -1327,7 +1326,7 @@ class GuildBan: """Used to represent guild bans.""" reason: typing.Optional[str] = attrs.field(repr=True) - """The reason for this ban, will be `None` if no reason was given.""" + """The reason for this ban, will be [`None`][] if no reason was given.""" user: users.User = attrs.field(repr=True) """The object of the user this ban targets.""" @@ -1357,14 +1356,14 @@ def __str__(self) -> str: @property def icon_url(self) -> typing.Optional[files.URL]: - """Icon URL for the guild, if set; otherwise `None`.""" + """Icon URL for the guild, if set; otherwise [`None`][].""" return self.make_icon_url() @property def shard_id(self) -> typing.Optional[int]: """Return the ID of the shard this guild is served by. - This may return `None` if the application does not have a gateway + This may return [`None`][] if the application does not have a gateway connection. """ if not isinstance(self.app, traits.ShardAware): @@ -1380,20 +1379,20 @@ def make_icon_url(self, *, ext: typing.Optional[str] = None, size: int = 4096) - Parameters ---------- ext : typing.Optional[str] - The extension to use for this URL, defaults to `png` or `gif`. + The extension to use for this URL. Supports `png`, `jpeg`, `jpg`, `webp` and `gif` (when animated). - If `None`, then the correct default extension is + 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. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- typing.Optional[hikari.files.URL] - The URL to the resource, or `None` if no icon is set. + The URL to the resource, or [`None`][] if no icon is set. Raises ------ @@ -1432,7 +1431,7 @@ async def ban( delete_message_seconds : hikari.undefined.UndefinedNoneOr[hikari.internal.time.Intervalish] If provided, the number of seconds to delete messages for. This can be represented as either an int/float between 0 and 604800 (7 days), or - a `datetime.timedelta` object. + a [`datetime.timedelta`][] object. reason : hikari.undefined.UndefinedOr[str] If provided, the reason that will be recorded in the audit logs. Maximum of 512 characters. @@ -1442,7 +1441,7 @@ async def ban( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `BAN_MEMBERS` permission. + If you are missing the [`hikari.permissions.Permissions.BAN_MEMBERS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -1479,7 +1478,7 @@ async def unban( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `BAN_MEMBERS` permission. + If you are missing the [`hikari.permissions.Permissions.BAN_MEMBERS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -1516,7 +1515,7 @@ async def kick( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `KICK_MEMBERS` permission. + If you are missing the [`hikari.permissions.Permissions.KICK_MEMBERS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -1576,18 +1575,18 @@ async def edit( If provided, the new afk timeout. icon : hikari.undefined.UndefinedOr[hikari.files.Resourceish] If provided, the new guild icon. Must be a 1024x1024 image or can be - an animated gif when the guild has the `ANIMATED_ICON` feature. + an animated gif when the guild has the [`hikari.guilds.GuildFeature.ANIMATED_ICON`][] feature. owner : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.users.PartialUser]]] If provided, the new guild owner. - .. warning:: + !!! warning You need to be the owner of the server to use this. splash : hikari.undefined.UndefinedNoneOr[hikari.files.Resourceish] If provided, the new guild splash. Must be a 16:9 image and the - guild must have the `INVITE_SPLASH` feature. + guild must have the [`hikari.guilds.GuildFeature.INVITE_SPLASH`][] feature. banner : hikari.undefined.UndefinedNoneOr[hikari.files.Resourceish] If provided, the new guild banner. Must be a 16:9 image and the - guild must have the `BANNER` feature. + guild must have the [`hikari.guilds.GuildFeature.BANNER`][] feature. system_channel : hikari.undefined.UndefinedNoneOr[hikari.snowflakes.SnowflakeishOr[hikari.channels.GuildTextChannel]] If provided, the new system channel. rules_channel : hikari.undefined.UndefinedNoneOr[hikari.snowflakes.SnowflakeishOr[hikari.channels.GuildTextChannel]] @@ -1613,7 +1612,7 @@ async def edit( If any of the fields that are passed have an invalid value. Or you are missing the hikari.errors.ForbiddenError - If you are missing the `MANAGE_GUILD` permission or if you tried to + If you are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission or if you tried to pass ownership without being the server owner. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). @@ -1673,7 +1672,7 @@ async def fetch_emoji(self, emoji: snowflakes.SnowflakeishOr[emojis_.CustomEmoji Parameters ---------- emoji : hikari.snowflakes.SnowflakeishOr[hikari.emojis.CustomEmoji] - The emoji to fetch. This can be a `hikari.emojis.CustomEmoji` + The emoji to fetch. This can be a [`hikari.emojis.CustomEmoji`][] or the ID of an existing emoji. Returns @@ -1760,7 +1759,7 @@ async def create_sticker( ) -> stickers.GuildSticker: """Create a sticker in a guild. - .. note:: + !!! note Lottie support is only available for verified and partnered servers. @@ -1793,7 +1792,8 @@ async def create_sticker( If any of the fields that are passed have an invalid value or if there are no more spaces for the sticker in the guild. hikari.errors.ForbiddenError - If you are missing `MANAGE_EMOJIS_AND_STICKERS` in the server. + If you are missing [`hikari.permissions.Permissions.MANAGE_GUILD_EXPRESSIONS`][] + in the server. hikari.errors.NotFoundError If the guild is not found. hikari.errors.UnauthorizedError @@ -1845,7 +1845,8 @@ async def edit_sticker( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing `MANAGE_EMOJIS_AND_STICKERS` in the server. + If you are missing [`hikari.permissions.Permissions.MANAGE_GUILD_EXPRESSIONS`][] + in the server. hikari.errors.NotFoundError If the guild or the sticker are not found. hikari.errors.UnauthorizedError @@ -1883,7 +1884,8 @@ async def delete_sticker( Raises ------ hikari.errors.ForbiddenError - If you are missing `MANAGE_EMOJIS_AND_STICKERS` in the server. + If you are missing [`hikari.permissions.Permissions.MANAGE_GUILD_EXPRESSIONS`][] + in the server. hikari.errors.NotFoundError If the guild or the sticker are not found. hikari.errors.UnauthorizedError @@ -1933,7 +1935,7 @@ async def create_category( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -2001,7 +2003,7 @@ async def create_text_channel( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -2077,7 +2079,7 @@ async def create_news_channel( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -2154,7 +2156,7 @@ async def create_forum_channel( This should be either 60, 1440, 4320 or 10080 minutes and, as of writing, ignores the parent channel's set default_auto_archive_duration - when passed as `hikari.undefined.UNDEFINED`. + when passed as [`hikari.undefined.UNDEFINED`][]. default_thread_rate_limit_per_user : hikari.undefined.UndefinedOr[hikari.internal.time.Intervalish] If provided, the ratelimit that should be set in threads created from the forum. @@ -2180,7 +2182,7 @@ async def create_forum_channel( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -2249,7 +2251,7 @@ async def create_voice_channel( If provided, the permission overwrites for the channel. region : hikari.undefined.UndefinedOr[typing.Union[hikari.voices.VoiceRegion, str]] If provided, the voice region to for this channel. Passing - `None` here will set it to "auto" mode where the used + [`None`][] here will set it to "auto" mode where the used region will be decided based on the first person who connects to it when it's empty. category : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.channels.GuildCategory]] @@ -2269,7 +2271,7 @@ async def create_voice_channel( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -2330,7 +2332,7 @@ async def create_stage_channel( If provided, the permission overwrites for the channel. region : hikari.undefined.UndefinedOr[typing.Union[hikari.voices.VoiceRegion, str]] If provided, the voice region to for this channel. Passing - `None` here will set it to "auto" mode where the used + [`None`][] here will set it to "auto" mode where the used region will be decided based on the first person who connects to it when it's empty. category : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.channels.GuildCategory]] @@ -2350,7 +2352,7 @@ async def create_stage_channel( hikari.errors.BadRequestError If any of the fields that are passed have an invalid value. hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -2378,10 +2380,10 @@ async def delete_channel( ) -> channels_.GuildChannel: """Delete a channel in the guild. - .. note:: + !!! note This method can also be used for deleting guild categories as well. - .. note:: + !!! note For Public servers, the set 'Rules' or 'Guidelines' channels and the 'Public Server Updates' channel cannot be deleted. @@ -2401,7 +2403,7 @@ async def delete_channel( hikari.errors.UnauthorizedError, or close a DM. If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `MANAGE_CHANNEL` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.MANAGE_CHANNELS`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -2464,7 +2466,7 @@ async def fetch_roles(self) -> typing.Sequence[Role]: @attrs.define(hash=True, kw_only=True, weakref_slot=False) class GuildPreview(PartialGuild): - """A preview of a guild with the `GuildFeature.DISCOVERABLE` feature.""" + """A preview of a guild with the [`hikari.guilds.GuildFeature.DISCOVERABLE`][] feature.""" features: typing.Sequence[typing.Union[str, GuildFeature]] = attrs.field(eq=False, hash=False, repr=False) """A list of the features in this guild.""" @@ -2505,11 +2507,11 @@ def make_discovery_splash_url(self, *, ext: str = "png", size: int = 4096) -> ty Parameters ---------- ext : str - The extension to use for this URL, defaults to `png`. + The extension to use for this URL. Supports `png`, `jpeg`, `jpg` and `webp`. size : int - The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- @@ -2534,16 +2536,16 @@ def make_splash_url(self, *, ext: str = "png", size: int = 4096) -> typing.Optio Parameters ---------- ext : str - The extension to use for this URL, defaults to `png`. + The extension to use for this URL. Supports `png`, `jpeg`, `jpg` and `webp`. size : int - The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- typing.Optional[hikari.files.URL] - The URL to the splash, or `None` if not set. + The URL to the splash, or [`None`][] if not set. Raises ------ @@ -2568,27 +2570,27 @@ class Guild(PartialGuild): application_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) """The ID of the application that created this guild. - This will always be `None` for guilds that weren't created by a bot. + This will always be [`None`][] for guilds that weren't created by a bot. """ afk_channel_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) """The ID for the channel that AFK voice users get sent to. - If `None`, then no AFK channel is set up for this guild. + If [`None`][], then no AFK channel is set up for this guild. """ afk_timeout: datetime.timedelta = attrs.field(eq=False, hash=False, repr=False) """Timeout for activity before a member is classed as AFK. How long a voice user has to be AFK for before they are classed as being - AFK and are moved to the AFK channel (`Guild.afk_channel_id`). + AFK and are moved to the AFK channel ([`hikari.guilds.Guild.afk_channel_id`][]). """ banner_hash: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) """The hash for the guild's banner. - This is only present if the guild has `GuildFeature.BANNER` in - `Guild.features` for this guild. For all other purposes, it is `None`. + This is only present if the guild has [`hikari.guilds.GuildFeature.BANNER`][] in + [`hikari.guilds.Guild.features`][] for this guild. For all other purposes, it is [`None`][]. """ default_message_notifications: typing.Union[GuildMessageNotificationsLevel, int] = attrs.field( @@ -2599,8 +2601,8 @@ class Guild(PartialGuild): description: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) """The guild's description. - This is only present if certain `GuildFeature`'s are set in - `Guild.features` for this guild. Otherwise, this will always be `None`. + This is only present if certain [`hikari.guilds.GuildFeature`][]'s are set in + [`hikari.guilds.Guild.features`][] for this guild. Otherwise, this will always be [`None`][]. """ discovery_splash_hash: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) @@ -2614,13 +2616,13 @@ class Guild(PartialGuild): is_widget_enabled: typing.Optional[bool] = attrs.field(eq=False, hash=False, repr=False) """Describes whether the guild widget is enabled or not. - If this information is not present, this will be `None`. + If this information is not present, this will be [`None`][]. """ max_video_channel_users: typing.Optional[int] = attrs.field(eq=False, hash=False, repr=False) """The maximum number of users allowed in a video channel together. - This information may not be present, in which case, it will be `None`. + This information may not be present, in which case, it will be [`None`][]. """ mfa_level: typing.Union[GuildMFALevel, int] = attrs.field(eq=False, hash=False, repr=False) @@ -2632,14 +2634,14 @@ class Guild(PartialGuild): preferred_locale: typing.Union[str, locales.Locale] = attrs.field(eq=False, hash=False, repr=False) """The preferred locale to use for this guild. - This can only be change if `GuildFeature.COMMUNITY` is in `Guild.features` + This can only be change if [`hikari.guilds.GuildFeature.COMMUNITY`][] is in [`hikari.guilds.Guild.features`][] for this guild and will otherwise default to `en-US`. """ premium_subscription_count: typing.Optional[int] = attrs.field(eq=False, hash=False, repr=False) """The number of nitro boosts that the server currently has. - This information may not be present, in which case, it will be `None`. + This information may not be present, in which case, it will be [`None`][]. """ premium_tier: typing.Union[GuildPremiumTier, int] = attrs.field(eq=False, hash=False, repr=False) @@ -2648,14 +2650,14 @@ class Guild(PartialGuild): public_updates_channel_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) """The channel ID of the channel where admins and moderators receive notices from Discord. - This is only present if `GuildFeature.COMMUNITY` is in `Guild.features` for - this guild. For all other purposes, it should be considered to be `None`. + This is only present if [`hikari.guilds.GuildFeature.COMMUNITY`][] is in [`hikari.guilds.Guild.features`][] for + this guild. For all other purposes, it should be considered to be [`None`][]. """ rules_channel_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) """The ID of the channel where rules and guidelines will be displayed. - If the `GuildFeature.COMMUNITY` feature is not defined, then this is `None`. + If the [`hikari.guilds.GuildFeature.COMMUNITY`][] feature is not defined, then this is [`None`][]. """ splash_hash: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) @@ -2668,7 +2670,7 @@ class Guild(PartialGuild): """ system_channel_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) - """The ID of the system channel or `None` if it is not enabled. + """The ID of the system channel or [`None`][] if it is not enabled. Welcome messages and Nitro boost messages may be sent to this channel. """ @@ -2676,8 +2678,8 @@ class Guild(PartialGuild): vanity_url_code: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) """The vanity URL code for the guild's vanity URL. - This is only present if `GuildFeature.VANITY_URL` is in `Guild.features` for - this guild. If not, this will always be `None`. + This is only present if [`hikari.guilds.GuildFeature.VANITY_URL`][] is in [`hikari.guilds.Guild.features`][] for + this guild. If not, this will always be [`None`][]. """ verification_level: typing.Union[GuildVerificationLevel, int] = attrs.field(eq=False, hash=False, repr=False) @@ -2687,7 +2689,7 @@ class Guild(PartialGuild): """The channel ID that the widget's generated invite will send the user to. If this information is unavailable or this is not enabled for the guild then - this will be `None`. + this will be [`None`][]. """ nsfw_level: GuildNSFWLevel = attrs.field(eq=False, hash=False, repr=False) @@ -2808,20 +2810,20 @@ def make_banner_url(self, *, ext: typing.Optional[str] = None, size: int = 4096) Parameters ---------- ext : typing.Optional[str] - The ext to use for this URL, defaults to `png` or `gif`. + The ext to use for this URL. Supports `png`, `jpeg`, `jpg`, `webp` and `gif` (when animated). - If `None`, then the correct default extension is + 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. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- typing.Optional[hikari.files.URL] - The URL of the banner, or `None` if no banner is set. + The URL of the banner, or [`None`][] if no banner is set. Raises ------ @@ -2852,7 +2854,7 @@ def make_discovery_splash_url(self, *, ext: str = "png", size: int = 4096) -> ty Supports `png`, `jpeg`, `jpg` and `webp`. size : int The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + Can be any power of two between `16` and `4096`. Returns ------- @@ -2881,12 +2883,12 @@ def make_splash_url(self, *, ext: str = "png", size: int = 4096) -> typing.Optio Supports `png`, `jpeg`, `jpg` and `webp`. size : int The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + Can be any power of two between `16` and `4096`. Returns ------- typing.Optional[hikari.files.URL] - The URL to the splash, or `None` if not set. + The URL to the splash, or [`None`][] if not set. Raises ------ @@ -2913,7 +2915,7 @@ def get_channel( Returns ------- typing.Optional[hikari.channels.GuildChannel] - The object of the guild channel found in cache or `None`. + The object of the guild channel found in cache or [`None`][]. """ if not isinstance(self.app, traits.CacheAware): return None @@ -2935,7 +2937,7 @@ def get_member(self, user: snowflakes.SnowflakeishOr[users.PartialUser]) -> typi Returns ------- typing.Optional[Member] - The cached member object if found, else `None`. + The cached member object if found, else [`None`][]. """ if not isinstance(self.app, traits.CacheAware): return None @@ -2948,7 +2950,7 @@ def get_my_member(self) -> typing.Optional[Member]: Returns ------- typing.Optional[Member] - The cached member for this guild, or `None` if not known. + The cached member for this guild, or [`None`][] if not known. """ if not isinstance(self.app, traits.ShardAware): return None @@ -2972,7 +2974,7 @@ def get_presence( Returns ------- typing.Optional[hikari.presences.MemberPresence] - The cached presence object if found, else `None`. + The cached presence object if found, else [`None`][]. """ if not isinstance(self.app, traits.CacheAware): return None @@ -2992,7 +2994,7 @@ def get_voice_state( Returns ------- typing.Optional[hikari.voices.VoiceState] - The cached voice state object if found, else `None`. + The cached voice state object if found, else [`None`][]. """ if not isinstance(self.app, traits.CacheAware): return None @@ -3013,7 +3015,7 @@ def get_emoji( ------- typing.Optional[hikari.emojis.KnownCustomEmoji] The object of the custom emoji if found in cache, else - `None`. + [`None`][]. """ if not isinstance(self.app, traits.CacheAware): return None @@ -3038,7 +3040,7 @@ def get_sticker( ------- typing.Optional[hikari.stickers.GuildSticker] The object of the sticker if found in cache, else - `None`. + [`None`][]. """ if not isinstance(self.app, traits.CacheAware): return None @@ -3060,7 +3062,7 @@ def get_role(self, role: snowflakes.SnowflakeishOr[PartialRole]) -> typing.Optio Returns ------- typing.Optional[Role] - The object of the role found in cache, else `None`. + The object of the role found in cache, else [`None`][]. """ if not isinstance(self.app, traits.CacheAware): return None @@ -3096,19 +3098,19 @@ async def fetch_owner(self) -> Member: async def fetch_widget_channel(self) -> typing.Optional[channels_.GuildChannel]: """Fetch the widget channel. - This will be `None` if not set. + This will be [`None`][] if not set. Returns ------- typing.Optional[hikari.channels.GuildChannel] - The channel the widget is linked to or else `None`. + The channel the widget is linked to or else [`None`][]. Raises ------ hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -3130,14 +3132,14 @@ async def fetch_afk_channel(self) -> typing.Optional[channels_.GuildVoiceChannel Returns ------- typing.Optional[hikari.channels.GuildVoiceChannel] - The AFK channel or `None` if not enabled. + The AFK channel or [`None`][] if not enabled. Raises ------ hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -3159,7 +3161,7 @@ async def fetch_system_channel(self) -> typing.Optional[channels_.GuildTextChann Returns ------- typing.Optional[hikari.channels.GuildTextChannel] - The system channel for this guild or `None` if not + The system channel for this guild or [`None`][] if not enabled. Raises @@ -3167,7 +3169,7 @@ async def fetch_system_channel(self) -> typing.Optional[channels_.GuildTextChann hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -3186,19 +3188,19 @@ async def fetch_system_channel(self) -> typing.Optional[channels_.GuildTextChann async def fetch_rules_channel(self) -> typing.Optional[channels_.GuildTextChannel]: """Fetch the channel where guilds display rules and guidelines. - If the `GuildFeature.COMMUNITY` feature is not defined, then this is `None`. + If the [`hikari.guilds.GuildFeature.COMMUNITY`][] feature is not defined, then this is [`None`][]. Returns ------- typing.Optional[hikari.channels.GuildTextChannel] - The channel where the rules of the guild are specified or else `None`. + The channel where the rules of the guild are specified or else [`None`][]. Raises ------ hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -3217,8 +3219,8 @@ async def fetch_rules_channel(self) -> typing.Optional[channels_.GuildTextChanne async def fetch_public_updates_channel(self) -> typing.Optional[channels_.GuildTextChannel]: """Fetch channel ID of the channel where admins and moderators receive notices from Discord. - This is only present if `GuildFeature.COMMUNITY` is in `Guild.features` for - this guild. For all other purposes, it should be considered to be `None`. + This is only present if [`hikari.guilds.GuildFeature.COMMUNITY`][] is in [`hikari.guilds.Guild.features`][] for + this guild. For all other purposes, it should be considered to be [`None`][]. Returns ------- @@ -3230,7 +3232,7 @@ async def fetch_public_updates_channel(self) -> typing.Optional[channels_.GuildT hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -3267,19 +3269,19 @@ class RESTGuild(Guild): approximate_active_member_count: typing.Optional[int] = attrs.field(eq=False, hash=False, repr=False) """The approximate number of members in the guild that are not offline. - This will be `None` when creating a guild. + This will be [`None`][] when creating a guild. """ approximate_member_count: typing.Optional[int] = attrs.field(eq=False, hash=False, repr=False) """The approximate number of members in the guild. - This will be `None` when creating a guild. + This will be [`None`][] when creating a guild. """ max_presences: typing.Optional[int] = attrs.field(eq=False, hash=False, repr=False) """The maximum number of presences for the guild. - If `None`, then there is no limit. + If [`None`][], then there is no limit. """ max_members: int = attrs.field(eq=False, hash=False, repr=False) @@ -3295,7 +3297,7 @@ class GatewayGuild(Guild): This information is only available if the guild was sent via a `GUILD_CREATE` event. If the guild is received from any other place, this will always be - `None`. + [`None`][]. The implications of a large guild are that presence information will not be sent about members who are offline or invisible. @@ -3306,7 +3308,7 @@ class GatewayGuild(Guild): This information is only available if the guild was sent via a `GUILD_CREATE` event. If the guild is received from any other place, this will always be - `None`. + [`None`][]. """ member_count: typing.Optional[int] = attrs.field(eq=False, hash=False, repr=False) @@ -3314,5 +3316,5 @@ class GatewayGuild(Guild): This information is only available if the guild was sent via a `GUILD_CREATE` event. If the guild is received from any other place, this will always be - `None`. + [`None`][]. """ diff --git a/hikari/impl/__init__.py b/hikari/impl/__init__.py index a631354b56..10f7d33ecb 100644 --- a/hikari/impl/__init__.py +++ b/hikari/impl/__init__.py @@ -22,7 +22,7 @@ # SOFTWARE. """Basic implementations of application components. -These components implement the interfaces in `hikari.api` to provide the +These components implement the interfaces in [`hikari.api`][] to provide the baseline functionality. For most applications that do not have bespoke performance or structural requirements, you will want to use these implementations. diff --git a/hikari/impl/buckets.py b/hikari/impl/buckets.py index 6f886b18fa..d998808bd7 100644 --- a/hikari/impl/buckets.py +++ b/hikari/impl/buckets.py @@ -35,16 +35,16 @@ What is the theory behind this implementation? ---------------------------------------------- -In this module, we refer to a `hikari.internal.routes.CompiledRoute` as a definition +In this module, we refer to a `CompiledRoute` as a definition of a route with specific major parameter values included (e.g. -`POST /channels/123/messages`), and a `hikari.internal.routes.Route` as a -definition of a route without specific parameter values included (e.g. -`POST /channels/{channel}/messages`). We can compile a -`hikari.internal.routes.CompiledRoute` from a `hikari.internal.routes.Route` -by providing the corresponding parameters as kwargs, as you may already know. +`POST /channels/123/messages`), and a `Route` as a definition of a route +without specific parameter values included +(e.g. `POST /channels/{channel}/messages`). We can create a `CompiledRoute` +from a `Route` by providing the corresponding parameters as kwargs, as you +may already know. In this module, a "bucket" is an internal data structure that tracks and -enforces the rate limit state for a specific `hikari.internal.routes.CompiledRoute`, +enforces the rate limit state for a specific `CompiledRoute`, and can manage delaying tasks in the event that we begin to get rate limited. It also supports providing in-order execution of queued tasks. @@ -63,18 +63,18 @@ Rate limits, on the other hand, apply to a bucket and are specific to the major parameters of the compiled route. This means that `POST /channels/123/messages` and `POST /channels/456/messages` do not share the same real bucket, despite -Discord providing the same bucket hash. A real bucket hash is the `str` hash of +Discord providing the same bucket hash. A real bucket hash is the string hash of the bucket that Discord sends us in a response concatenated to the corresponding major parameters. This is used for quick bucket indexing internally in this module. One issue that occurs from this is that we cannot effectively hash a -`hikari.internal.routes.CompiledRoute` that has not yet been hit, meaning that +`CompiledRoute` that has not yet been hit, meaning that until we receive a response from this endpoint, we have no idea what our rate limits could be, nor the bucket that they sit in. This is usually not problematic, as the first request to an endpoint should never be rate limited unless you are hitting it from elsewhere in the same time window outside your -hikari.applications. To manage this situation, unknown endpoints are allocated to +[`hikari.applications`][]. To manage this situation, unknown endpoints are allocated to a special unlimited bucket until they have an initial bucket hash code allocated from a response. Once this happens, the route is reallocated a dedicated bucket. Unknown buckets have a hardcoded initial hash code internally. @@ -82,24 +82,24 @@ Initially acquiring time on a bucket ------------------------------------ -Each time you `BaseRateLimiter.acquire()` a request timeslice for a given -`hikari.internal.routes.Route`, several things happen. The first is that we +Each time you call [`hikari.impl.buckets.RESTBucket.acquire`][] a request +timeslice for a given `Route`, several things happen. The first is that we attempt to find the existing bucket for that route, if there is one, or get an unknown bucket otherwise. This is done by creating a real bucket hash from the compiled route. The initial hash is calculated using a lookup table that maps -`hikari.internal.routes.CompiledRoute` objects to their corresponding initial hash +`CompiledRoute` objects to their corresponding initial hash codes, or to the unknown bucket hash code if not yet known. This initial hash is -processed by the `hikari.internal.routes.CompiledRoute` to provide the real bucket +processed by the `CompiledRoute` to provide the real bucket hash we need to get the route's bucket object internally. -The `BaseRateLimiter.acquire()` method will take the bucket and acquire a new -timeslice on it. This takes the form of a `asyncio.Future` which should be -awaited by the caller and will complete once the caller is allowed to make a -request. Most of the time, this is done instantly, but if the bucket has an -active rate limit preventing requests being sent, then the future will be paused -until the rate limit is over. This may be longer than the rate limit period if -you have queued a large number of requests during this limit, as it is -first-come-first-served. +The [`hikari.impl.buckets.RESTBucket.acquire`][] method will take the +bucket and acquire a new timeslice on it. This takes the form of a +[`asyncio.Future`][] that is awaited and will complete once the caller is allowed +to make a request. Most of the time, this is done instantly, but if the bucket +has an active rate limit preventing requests being sent, then the future will +be paused until the rate limit is over. This may be longer than the rate limit +period if you have queued a large number of requests during this limit, as it +is first-come-first-served. Acquiring a rate limited bucket will start a bucket-wide task (if not already running) that will wait until the rate limit has completed before allowing more @@ -108,10 +108,12 @@ tidies itself up and disposes of itself. This task will complete once the queue becomes empty. -The result of `RESTBucketManager.acquire()` is a tuple of a `asyncio.Future` to -await on which completes when you are allowed to proceed with making a request, -and a real bucket hash which should be stored temporarily. This will be -explained in the next section. +The result of [`hikari.impl.buckets.RESTBucketManager.acquire_bucket`][] is an async +context manager that must be acquired during the entirety of the request and +released once it is done (in reality, it is just a +[`hikari.impl.buckets.RESTBucket`][], but we want the ratelimit update to be +forced through [`hikari.impl.buckets.RESTBucketManager.update_rate_limits`][] +to keep proper state) Handling the rate limit headers of a response --------------------------------------------- @@ -121,18 +123,19 @@ These headers are: * `X-RateLimit-Limit`: - an `int` describing the max requests in the bucket from empty to + an [`int`][] describing the max requests in the bucket from empty to being rate limited. * `X-RateLimit-Remaining`: - an `int` describing the remaining number of requests before rate + an [`int`][] describing the remaining number of requests before rate limiting occurs in the current window. * `X-RateLimit-Bucket`: - a `str` containing the initial bucket hash. + a [`str`][] containing the initial bucket hash. * `X-RateLimit-Reset-After`: - a `float` containing the number of seconds when the current rate + a [`float`][] containing the number of seconds when the current rate limit bucket will reset with decimal millisecond precision. -Each of the above values should be passed to the `update_rate_limits` method to +Each of the above values should be passed to the +[`hikari.impl.buckets.RESTBucketManager.update_rate_limits`][] method to ensure that the bucket you acquired time from is correctly updated should Discord decide to alter their ratelimits on the fly without warning (including timings and the bucket). @@ -143,17 +146,17 @@ Tidying up ---------- -To prevent unused buckets cluttering up memory, each `RESTBucketManager` -instance spins up a `asyncio.Task` that periodically locks the bucket list +To prevent unused buckets cluttering up memory, each [`hikari.impl.buckets.RESTBucketManager`][] +instance spins up a [`asyncio.Task`][] that periodically locks the bucket list (not threadsafe, only using the concept of asyncio not yielding in regular functions) and disposes of any clearly stale buckets that are no longer needed. These will be recreated again in the future if they are needed. -When shutting down an application, one must remember to `close()` the -`RESTBucketManager` that has been used. This will ensure the garbage collection -task is stopped, and will also ensure any remaining futures in any bucket queues -have an `asyncio.CancelledError` set on them to prevent deadlocking ratelimited -calls that may be waiting to be unlocked. +When shutting down an application, one must remember to call +[`hikari.impl.buckets.RESTBucketManager.close`][]. This will ensure the +garbage collection task is stopped, and will also ensure any remaining futures +in any bucket queues have an [`asyncio.CancelledError`][] set on them to prevent +deadlocking ratelimited calls that may be waiting to be unlocked. Body-field-specific rate limiting --------------------------------- @@ -165,21 +168,27 @@ No information is sent in headers about these specific limits. You will only be made aware that they exist once you get ratelimited. In the 429 ratelimited -response, you will have the `"global"` attribute set to `False`, and a +response, you will have the `"global"` attribute set to [`False`][], and a `"reset_after"` attribute that differs entirely to the `X-RateLimit-Reset-After` header. Thus, it is important to not assume the value in the 429 response -for the reset time is the same as the one in the bucket headers. Hikari's -`hikari.api.rest.RESTClient` implementation specifically uses the value furthest -in the future when working out which bucket to adhere to. +for the reset time is the same as the one in the bucket headers. hikari's +[`hikari.api.rest.RESTClient`][] implementation specifically uses the value +furthest in the future when working out which bucket to adhere to. It is worth remembering that there is an API limit to the number of 401s, 403s, and 429s you receive, which is around 10,000 per 15 minutes. Passing this limit results in a soft ban of your account. -At the time of writing, the only example of this appears to be on the -`PATCH /channels/{channel_id}` endpoint. This has a limit of two changes per -10 minutes. More details about how this is implemented have yet to be -released or documented... +The true nature of these limits are not known and Discord staff have repeatedly +pointed to them never being documented for the sake of system integrity. +These special ratelimits are not something a normal user should encounter +unless they are calling a single route multiple times with the end goal +of editing a single attribute in quick succession. It is up to Discord's +discretion on what is considered as "spammy" behaviour and one they would +not like to allow on their API. + +These ratelimits should not be "properly" handled and instead be avoided +completely by the end developer (similar to Cloudflare 429s). """ from __future__ import annotations @@ -211,7 +220,7 @@ class RESTBucket(rate_limits.WindowedBurstRateLimiter): Component to represent an active rate limit bucket on a specific HTTP route with a specific major parameter combo. - This is somewhat similar to the `WindowedBurstRateLimiter` in how it + This is somewhat similar to the [`hikari.impl.rate_limits.WindowedBurstRateLimiter`][] in how it works. This algorithm will use fixed-period time windows that have a given limit @@ -223,7 +232,7 @@ class RESTBucket(rate_limits.WindowedBurstRateLimiter): capacity to zero, and tasks that are queued will start being able to drip again. - Additional logic is provided by the `RESTBucket.update_rate_limit` call + Additional logic is provided by the [`hikari.impl.buckets.RESTBucket.update_rate_limit`][] call which allows dynamically changing the enforced rate limits at any time. """ @@ -255,7 +264,7 @@ async def __aexit__( @property def is_unknown(self) -> bool: - """Return `True` if the bucket represents an `UNKNOWN` bucket.""" + """Whether it represents an UNKNOWN bucket.""" return self.name.startswith(UNKNOWN_HASH) def release(self) -> None: @@ -265,10 +274,10 @@ def release(self) -> None: async def acquire(self) -> None: """Acquire time and the lock on this bucket. - .. note:: - You should afterwards invoke `RESTBucket.update_rate_limit` to + !!! note + You should afterwards invoke [`hikari.impl.buckets.RESTBucket.update_rate_limit`][] to update any rate limit information you are made aware of and - `RESTBucket.release` to release the lock. + [`hikari.impl.buckets.RESTBucket.release`][] to release the lock. Raises ------ @@ -317,9 +326,9 @@ async def acquire(self) -> None: def update_rate_limit(self, remaining: int, limit: int, reset_at: float) -> None: """Update the rate limit information. - .. note:: - The `reset_at` epoch is expected to be a `time.monotonic` - monotonic epoch, rather than a `time.time` date-based epoch. + !!! note + The `reset_at` epoch is expected to be a [`time.monotonic`][] + monotonic epoch, rather than a [`time.time`][] date-based epoch. Parameters ---------- @@ -410,14 +419,13 @@ def start(self, poll_period: float = 20.0, expire_after: float = 10.0) -> None: Parameters ---------- poll_period : float - Period to poll the garbage collector at in seconds. Defaults - to `20` seconds. + Period to poll the garbage collector at in seconds. expire_after : float - Time after which the last `reset_at` was hit for a bucket to + Time after which the last [`hikari.impl.buckets.RESTBucket.reset_at`][] was hit for a bucket to remove it. Higher values will retain unneeded ratelimit info for longer, but may produce more effective rate-limiting logic as a result. Using `0` will make the bucket get garbage collected as soon - as the rate limit has reset. Defaults to `10` seconds. + as the rate limit has reset. """ if self._gc_task: raise errors.ComponentStateConflictError("Cannot start an active bucket manager") @@ -499,9 +507,9 @@ def acquire_bucket( ) -> typing.AsyncContextManager[None]: """Acquire a bucket for the given route. - .. note:: + !!! note You MUST keep the context manager acquired during the full duration - of the request: from making the request until calling `update_rate_limits`. + of the request: from making the request until calling [`hikari.impl.buckets.RESTBucket.update_rate_limit`][]. Parameters ---------- @@ -554,11 +562,11 @@ def update_rate_limits( bucket_header : str The `X-RateLimit-Bucket` header that was provided in the response. remaining_header : int - The `X-RateLimit-Remaining` header cast to an `int`. + The `X-RateLimit-Remaining` header cast to an [`int`][]. limit_header : int - The `X-RateLimit-Limit` header cast to an `int`. + The `X-RateLimit-Limit` header cast to an [`int`][]. reset_after : float - The `X-RateLimit-Reset-After` header cast to a `float`. + The `X-RateLimit-Reset-After` header cast to a [`float`][]. """ if not self._gc_task: raise errors.ComponentStateConflictError("Cannot interact with an inactive bucket manager") diff --git a/hikari/impl/config.py b/hikari/impl/config.py index c7fc36b372..168625d6d1 100644 --- a/hikari/impl/config.py +++ b/hikari/impl/config.py @@ -67,7 +67,7 @@ class BasicAuthHeader: username: str = attrs.field(validator=attrs.validators.instance_of(str)) """Username for the header. - .. warning:: + !!! warning This must not contain `":"`. """ @@ -100,14 +100,14 @@ class ProxySettings(config.ProxySettings): auth: typing.Any = attrs.field(default=None) """Authentication header value to use. - When cast to a `str`, this should provide the full value + When cast to a [`str`][], this should provide the full value for the authentication header. If you are using basic auth, you should consider using the - `BasicAuthHeader` helper object here, as this will provide any - transformations you may require into a base64 string. + [`hikari.impl.config.BasicAuthHeader`][] helper object here, as this will + provide any transformations you may require into a Base64 string. - The default is to have this set to `None`, which will + The default is to have this set to [`None`][], which will result in no authentication being provided. """ @@ -117,21 +117,21 @@ class ProxySettings(config.ProxySettings): url: typing.Union[None, str] = attrs.field(default=None) """Proxy URL to use. - Defaults to `None` which disables the use of an explicit proxy. + Defaults to [`None`][] which disables the use of an explicit proxy. """ trust_env: bool = attrs.field(default=False, validator=attrs.validators.instance_of(bool)) """Toggle whether to look for a `netrc` file or environment variables. - If `True`, and no `url` is given on this object, then + 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. + If [`False`][], then this information is instead ignored. - Defaults to `False` to prevent potentially unwanted behavior. + Defaults to [`False`][] to prevent potentially unwanted behavior. - .. note:: + !!! note For more details of using `netrc`, visit: """ @@ -140,7 +140,7 @@ class ProxySettings(config.ProxySettings): def all_headers(self) -> typing.Optional[data_binding.Headers]: """Return all proxy headers. - Will be `None` if no headers are to be send with any request. + Will be [`None`][] if no headers are to be send with any request. """ if self.headers is None: if self.auth is None: @@ -160,28 +160,28 @@ class HTTPTimeoutSettings: acquire_and_connect: typing.Optional[float] = attrs.field(default=None) """Timeout for `request_socket_connect` PLUS connection acquisition. - By default, this has no timeout allocated. Setting it to `None` + By default, this has no timeout allocated. Setting it to [`None`][] will disable it. """ request_socket_connect: typing.Optional[float] = attrs.field(default=None) """Timeout for connecting a socket. - By default, this has no timeout allocated. Setting it to `None` + By default, this has no timeout allocated. Setting it to [`None`][] will disable it. """ request_socket_read: typing.Optional[float] = attrs.field(default=None) """Timeout for reading a socket. - By default, this has no timeout allocated. Setting it to `None` + By default, this has no timeout allocated. Setting it to [`None`][] will disable it. """ total: typing.Optional[float] = attrs.field(default=30.0) """Total timeout for entire request. - By default, this has a 30 second timeout allocated. Setting it to `None` + By default, this has a 30 second timeout allocated. Setting it to [`None`][] will disable it. """ @@ -204,29 +204,29 @@ class HTTPSettings(config.HTTPSettings): enable_cleanup_closed: bool = attrs.field(default=False, validator=attrs.validators.instance_of(bool)) """Toggle whether to clean up closed transports. - This defaults to `False` to combat various protocol and asyncio + This defaults to [`False`][] to combat various protocol and asyncio issues present. If you are sure you know what you are doing, - you may instead set this to `True` to enable this + you may instead set this to [`True`][] to enable this behavior internally. """ force_close_transports: bool = attrs.field(default=True, validator=attrs.validators.instance_of(bool)) """Toggle whether to force close transports on shut down. - This defaults to `True` to combat various protocol and asyncio + This defaults to [`True`][] to combat various protocol and asyncio issues present when using Microsoft Windows. If you are sure you know - what you are doing, you may instead set this to `False` to disable this + what you are doing, you may instead set this to [`False`][] to disable this behavior internally. """ max_redirects: typing.Optional[int] = attrs.field(default=10) """Behavior for handling redirect HTTP responses. - If a `int`, allow following redirects from `3xx` 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. + If [`None`][], then disallow any redirects. The default is to disallow this behavior for security reasons. @@ -234,7 +234,7 @@ class HTTPSettings(config.HTTPSettings): future where you need to enable this if Discord change their URL without warning. - .. note:: + !!! note This will only apply to the REST API. WebSockets remain unaffected by any value set here. """ @@ -253,24 +253,24 @@ def _(self, _: attrs.Attribute[typing.Optional[int]], value: typing.Any) -> None ) """SSL context to use. - This may be assigned a `bool` or an `ssl.SSLContext` object. + This may be assigned a [`bool`][] or an [`ssl.SSLContext`][] object. - If assigned to `True`, a default SSL context is generated by + 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 + 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. + If an instance of [`ssl.SSLContext`][], then this context will be used. - .. warning:: + !!! 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:: + !!! 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 @@ -307,7 +307,7 @@ class CacheSettings(config.CacheSettings): ) """The cache components to use. - Defaults to `hikari.api.cache.CacheComponents.ALL`. + Defaults to [`hikari.api.config.CacheComponents.ALL`][]. """ max_messages: int = attrs.field(default=300) @@ -332,5 +332,5 @@ class CacheSettings(config.CacheSettings): Useful when only the bot member is required (eg. permission checks). This will have no effect if the members cache is not enabled. - Defaults to `False`. + Defaults to [`False`][]. """ diff --git a/hikari/impl/entity_factory.py b/hikari/impl/entity_factory.py index 7e6764f882..3d17441cc2 100644 --- a/hikari/impl/entity_factory.py +++ b/hikari/impl/entity_factory.py @@ -1655,27 +1655,27 @@ def serialize_embed( # noqa: C901 - Function too complex # Yep, these are technically two unreachable branches. However, this is an incredibly # common mistake to make when working with embeds and not using a static type # checker, so I have added these as additional safeguards for UX and ease - # of debugging. The case that there are `None` should be detected immediately by + # of debugging. The case that there are [`None`][] should be detected immediately by # static type checkers, regardless. name = str(field.name) if field.name is not None else None value = str(field.value) if field.value is not None else None if name is None: - raise TypeError(f"in embed.fields[{i}].name - cannot have `None`") + raise TypeError(f"in embed.fields[{i}].name - cannot have [`None`][]") if not name: raise TypeError(f"in embed.fields[{i}].name - cannot have empty string") if not name.strip(): raise TypeError(f"in embed.fields[{i}].name - cannot have only whitespace") if value is None: - raise TypeError(f"in embed.fields[{i}].value - cannot have `None`") + raise TypeError(f"in embed.fields[{i}].value - cannot have [`None`][]") if not value: raise TypeError(f"in embed.fields[{i}].value - cannot have empty string") if not value.strip(): raise TypeError(f"in embed.fields[{i}].value - cannot have only whitespace") # Name and value always have to be specified; we can always - # send a default `inline` value also just to keep this simpler. + # send a default [`inline`][] value also just to keep this simpler. field_payloads.append({"name": name, "value": value, "inline": field.is_inline}) payload["fields"] = field_payloads diff --git a/hikari/impl/event_manager.py b/hikari/impl/event_manager.py index e9ec111adc..ab10315232 100644 --- a/hikari/impl/event_manager.py +++ b/hikari/impl/event_manager.py @@ -368,16 +368,16 @@ async def on_guild_create( # noqa: C901, CFQ001 - Function too complex and too # We only want to chunk if we are allowed and need to: # Allowed? # All the following must be true: - # 1. `auto_chunk_members` is true (the user wants us to). - # 2. We have the necessary intents (`GUILD_MEMBERS`). - # 3. The guild is marked as "large" or we do not have `GUILD_PRESENCES` intent + # 1. [`auto_chunk_members`][] is true (the user wants us to). + # 2. We have the necessary intents ([`GUILD_MEMBERS`][]). + # 3. The guild is marked as "large" or we do not have [`GUILD_PRESENCES`][] intent # Discord will only send every other member objects on the `GUILD_CREATE` # payload if presence intents are also declared, so if this isn't the case then we also # want to chunk small guilds. # # Need to? # One of the following must be true: - # 1. We have a cache, and it requires it (it is enabled for `MEMBERS`), but we are + # 1. We have a cache, and it requires it (it is enabled for [`MEMBERS`][]), but we are # not limited to only our own member (which is included in the `GUILD_CREATE` payload). # 2. The user is waiting for the member chunks (there is an event listener for it). presences_declared = self._intents & intents_.Intents.GUILD_PRESENCES diff --git a/hikari/impl/event_manager_base.py b/hikari/impl/event_manager_base.py index 5d3e86db55..93c5888f9c 100644 --- a/hikari/impl/event_manager_base.py +++ b/hikari/impl/event_manager_base.py @@ -116,10 +116,10 @@ async def call_weak_method(event: base_events.Event) -> None: class EventStream(event_manager_.EventStream[base_events.EventT]): - """An implementation of an event `EventStream` class. + """An implementation of an event [`hikari.api.event_manager.EventStream`][] class. - .. note:: - While calling `EventStream.filter` on an active "opened" event stream + !!! note + While calling [`hikari.impl.event_manager_base.EventStream.filter`][] on an active "opened" event stream will return a wrapping lazy iterator, calling it on an inactive "closed" event stream will return the event stream and add the given predicates to the streamer. @@ -277,7 +277,6 @@ def filtered( ---------------- cache_components : hikari.api.config.CacheComponents Bitfield of the cache components this event may make altering calls to. - This defaults to `hikari.api.config.CacheComponents.NONE`. """ if isinstance(event_types, typing.Sequence): # dict.fromkeys is used to remove any duplicate entries here @@ -430,7 +429,7 @@ def subscribe( ): raise TypeError("Cannot subscribe a non-coroutine function callback") - # `_nested` is used to show the correct source code snippet if an intent + # [`_nested`][] is used to show the correct source code snippet if an intent # warning is triggered. self._check_event(event_type, _nested) diff --git a/hikari/impl/gateway_bot.py b/hikari/impl/gateway_bot.py index 6ff48a1cac..82b24b511e 100644 --- a/hikari/impl/gateway_bot.py +++ b/hikari/impl/gateway_bot.py @@ -109,12 +109,12 @@ class GatewayBot(traits.GatewayBotAware): This is the class you will want to use to start, control, and build a bot with. - .. note:: + !!! note Settings that control the gateway session are provided to the - `GatewayBot.run` and `GatewayBot.start` functions in this class. This is done - to allow you to contextually customise details such as sharding - configuration without having to re-initialize the entire application - each time. + [`hikari.impl.gateway_bot.GatewayBot.run`][] and [`hikari.impl.gateway_bot.GatewayBot.start`][] + functions in this class. This is done to allow you to contextually + customise details such as sharding configuration without having to + re-initialize the entire application each time. Parameters ---------- @@ -124,8 +124,7 @@ class GatewayBot(traits.GatewayBotAware): Other Parameters ---------------- allow_color : bool - Defaulting to `True`, this will enable coloured console logs - on any platform that is a TTY. + Whether enable coloured console logs will be enabled on any platform that is a TTY. Setting a `"CLICOLOR"` environment variable to any **non `0`** value will override this setting. @@ -135,27 +134,27 @@ class GatewayBot(traits.GatewayBotAware): explicitly disable this is provided. See `force_color` for an alternative. banner : typing.Optional[str] - The package to search for a `banner.txt` in. Defaults to `"hikari"` for - the `"hikari/banner.txt"` banner. - Setting this to `None` will disable the banner being shown. + The package to search for a `banner.txt` in. + + Setting this to [`None`][] will disable the banner being shown. suppress_optimization_warning : bool - Defaults to `False`. By default, Hikari warns you if you are not running - your bot using optimizations (`-O` or `-OO`). If this is `True`, you won't + By default, hikari warns you if you are not running + your bot using optimizations (`-O` or `-OO`). If this is [`True`][], you won't receive these warnings, even if you are not running using optimizations. executor : typing.Optional[concurrent.futures.Executor] - Defaults to `None`. If non-`None`, then this executor - is used instead of the `concurrent.futures.ThreadPoolExecutor` attached - to the `asyncio.AbstractEventLoop` that the bot will run on. This + If non-[`None`][], then this executor + is used instead of the [`concurrent.futures.ThreadPoolExecutor`][] attached + to the [`asyncio.AbstractEventLoop`][] that the bot will run on. This executor is used primarily for file-IO. - While mainly supporting the `concurrent.futures.ThreadPoolExecutor` + While mainly supporting the [`concurrent.futures.ThreadPoolExecutor`][] implementation in the standard lib, Hikari's file handling systems - should also work with `concurrent.futures.ProcessPoolExecutor`, which + should also work with [`concurrent.futures.ProcessPoolExecutor`][], which relies on all objects used in IPC to be pickleable. Many third-party libraries will not support this fully though, so your mileage may vary on using ProcessPoolExecutor implementations with this parameter. force_color : bool - Defaults to `False`. If `True`, then this application + If [`True`][], then this application will __force__ colour to be used in console-based output. Specifying a `"CLICOLOR_FORCE"` environment variable with a non-`"0"` value will override this setting. @@ -166,56 +165,58 @@ class GatewayBot(traits.GatewayBotAware): http_settings : typing.Optional[hikari.impl.config.HTTPSettings] Optional custom HTTP configuration settings to use. Allows you to customise functionality such as whether SSL-verification is enabled, - what timeouts `aiohttp` should expect to use for requests, and behavior + what timeouts [`aiohttp`][] should expect to use for requests, and behavior regarding HTTP-redirects. intents : hikari.intents.Intents - Defaults to `hikari.intents.Intents.ALL_UNPRIVILEGED`. This allows you + This allows you to change which intents your application will use on the gateway. This can be used to control and change the types of events you will receive. auto_chunk_members : bool - Defaults to `True`. If `False`, then no member chunks - will be requested automatically, even if there are reasons to do so. + If [`False`][], then no member chunks will be requested automatically, + even if there are reasons to do so. - We only want to chunk if we are allowed and need to: + We only want to chunk if we both are allowed and need to: - Allowed? All the following must be true: - 1. `auto_chunk_members` is true (the user wants us to). - 2. We have the necessary intents (`GUILD_MEMBERS`). - 3. The guild is marked as "large" or we do not have `GUILD_PRESENCES` intent - Discord will only send every other member objects on the `GUILD_CREATE` - payload if presence intents are also declared, so if this isn't the case then we also - want to chunk small guilds. + 1. `auto_chunk_members` is [`True`][] (the user wants us to). + 2. We have the necessary intents ([`hikari.intents.Intents.GUILD_MEMBERS`][]). + 3. The guild is marked as "large" or we do not have + [`hikari.intents.Intents.GUILD_PRESENCES`][] intent Discord will + only send every other member objects on the `GUILD_CREATE` + payload if presence intents are also declared, so if this + isn't the case then we also want to chunk small guilds. - Needed? One of the following must be true: - 1. We have a cache, and it requires it (it is enabled for `MEMBERS`), but we are - not limited to only our own member (which is included in the `GUILD_CREATE` payload). - 2. The user is waiting for the member chunks (there is an event listener for it). + 1. We have a cache, and it requires it (it is enabled for + [`hikari.api.CacheComponents.MEMBERS`][]), but we are not limited + to only our own member (which is included in the `GUILD_CREATE` + payload). + 2. The user is waiting for the member chunks (there is an event + listener for it). logs : typing.Union[None, str, int, typing.Dict[str, typing.Any], os.PathLike] The flavour to set the logging to. - This can be `None` to not enable logging automatically. + This can be [`None`][] to not enable logging automatically. - If you pass a `str` or a `int`, it is interpreted as + If you pass a [`str`][] or a [`int`][], it is interpreted as the global logging level to use, and should match one of `"DEBUG"`, `"INFO"`, `"WARNING"`, `"ERROR"` or `"CRITICAL"`. The configuration will be set up to use a `colorlog` coloured logger, and to use a sane logging format strategy. The output will be written - to `sys.stdout` using this configuration. + to [`sys.stdout`][] using this configuration. - If you pass a `dict`, it is treated as the mapping to pass to - `logging.config.dictConfig`. If the dict defines any handlers, default + If you pass a [`dict`][], it is treated as the mapping to pass to + [`logging.config.dictConfig`][]. If the dict defines any handlers, default handlers will not be setup if `incremental` is not specified. - If you pass a `str` to an existing file or a `os.PathLike`, it is - interpreted as the file to load config from using `logging.config.fileConfig`. + If you pass a [`str`][] to an existing file or a [`os.PathLike`][], it is + interpreted as the file to load config from using [`logging.config.fileConfig`][]. Note that `"TRACE_HIKARI"` is a library-specific logging level which is expected to be more verbose than `"DEBUG"`. - Defaults to `"INFO"`. - max_rate_limit : float The max number of seconds to backoff for when rate limited. Anything greater than this will instead raise an error. @@ -231,16 +232,18 @@ class GatewayBot(traits.GatewayBotAware): that may be in use. max_retries : typing.Optional[int] Maximum number of times a request will be retried if - it fails with a `5xx` status. Defaults to 3 if set to `None`. + it fails with a `5xx` status. + + Will default to 3 if set to [`None`][]. proxy_settings : typing.Optional[hikari.impl.config.ProxySettings] Custom proxy settings to use with network-layer logic in your application to get through an HTTP-proxy. dumps : hikari.internal.data_binding.JSONEncoder - The JSON encoder this application should use. Defaults to `hikari.internal.data_binding.default_json_dumps`. + The JSON encoder this application should use. loads : hikari.internal.data_binding.JSONDecoder - The JSON decoder this application should use. Defaults to `hikari.internal.data_binding.default_json_loads`. + The JSON decoder this application should use. rest_url : typing.Optional[str] - Defaults to the Discord REST API URL if `None`. Can be + Defaults to the Discord REST API URL if [`None`][]. Can be overridden if you are attempting to point to an unofficial endpoint, or if you are attempting to mock/stub the Discord API for any reason. Generally you do not want to change this. @@ -249,23 +252,22 @@ class GatewayBot(traits.GatewayBotAware): -------- Simple logging setup: - .. code-block:: python - + ```py hikari.GatewayBot("TOKEN", logs="INFO") # Registered logging level # or hikari.GatewayBot("TOKEN", logs=20) # Logging level as an int + ``` File config: - .. code-block:: python - + ```py # See https://docs.python.org/3/library/logging.config.html#configuration-file-format for more info hikari.GatewayBot("TOKEN", logs="path/to/file.ini") + ``` Setting up logging through a dict config: - .. code-block:: python - + ```py # See https://docs.python.org/3/library/logging.config.html#dictionary-schema-details for more info hikari.GatewayBot( "TOKEN", @@ -278,6 +280,7 @@ class GatewayBot(traits.GatewayBotAware): }, } ) + ``` """ shards: typing.Mapping[int, gateway_shard.GatewayShard] @@ -499,10 +502,9 @@ def dispatch(self, event: base_events.Event) -> asyncio.Future[typing.Any]: Examples -------- We can dispatch custom events by first defining a class that - derives from `hikari.events.base_events.Event`. - - .. code-block:: python + derives from [`hikari.events.base_events.Event`][]. + ```py import attrs from hikari.traits import RESTAware @@ -525,11 +527,11 @@ class EveryoneMentionedEvent(Event): channel_id: Snowflake = attrs.field() '''The channel ID.''' + ``` We can then dispatch our event as we see fit. - .. code-block:: python - + ```py from hikari.events.messages import MessageCreateEvent @bot.listen(MessageCreateEvent) @@ -543,15 +545,16 @@ async def on_message(event): ) bot.dispatch(event) + ``` This event can be listened to elsewhere by subscribing to it with - `hikari.impl.event_manager_base.EventManager.subscribe`. - - .. code-block:: python + [`hikari.impl.event_manager_base.EventManagerBase.subscribe`][]. + ```py @bot.listen(EveryoneMentionedEvent) async def on_everyone_mentioned(event): print(event.user, "just pinged everyone in", event.channel_id) + ``` Returns ------- @@ -563,11 +566,11 @@ async def on_everyone_mentioned(event): See Also -------- - Listen : `hikari.impl.gateway_bot.GatewayBot.listen`. - Stream : `hikari.impl.gateway_bot.GatewayBot.stream`. - Subscribe : `hikari.impl.gateway_bot.GatewayBot.subscribe`. - Unsubscribe : `hikari.impl.gateway_bot.GatewayBot.unsubscribe`. - Wait_for : `hikari.impl.gateway_bot.GatewayBot.wait_for`. + Listen : [`hikari.impl.gateway_bot.GatewayBot.listen`][]. + Stream : [`hikari.impl.gateway_bot.GatewayBot.stream`][]. + Subscribe : [`hikari.impl.gateway_bot.GatewayBot.subscribe`][]. + Unsubscribe : [`hikari.impl.gateway_bot.GatewayBot.unsubscribe`][]. + Wait_for : [`hikari.impl.gateway_bot.GatewayBot.wait_for`][]. """ return self._event_manager.dispatch(event) @@ -580,12 +583,11 @@ def get_listeners( ---------- event_type : typing.Type[EventT] The event type to look for. - `EventT` must be a subclass of `hikari.events.base_events.Event`. + `EventT` must be a subclass of [`hikari.events.base_events.Event`][]. polymorphic : bool - If `True`, this will also return the listeners of the - subclasses of the given event type. If `False`, then - only listeners for this class specifically are returned. The - default is `True`. + If [`True`][], this will also return the listeners of the + subclasses of the given event type. If [`False`][], then + only listeners for this class specifically are returned. Returns ------- @@ -615,22 +617,22 @@ def listen( to be undefined. If this is the case, the event type will be inferred instead from the type hints on the function signature. - `EventT` must be a subclass of `hikari.events.base_events.Event`. + `EventT` must be a subclass of [`hikari.events.base_events.Event`][]. Returns ------- typing.Callable[[EventT], EventT] A decorator for a coroutine function that passes it to - `EventManager.subscribe` before returning the function + [`hikari.impl.event_manager.EventManagerImpl.subscribe`][] before returning the function reference. See Also -------- - Dispatch : `hikari.impl.gateway_bot.GatewayBot.dispatch`. - Stream : `hikari.impl.gateway_bot.GatewayBot.stream`. - Subscribe : `hikari.impl.gateway_bot.GatewayBot.subscribe`. - Unsubscribe : `hikari.impl.gateway_bot.GatewayBot.unsubscribe`. - Wait_for : `hikari.impl.gateway_bot.GatewayBot.wait_for`. + Dispatch : [`hikari.impl.gateway_bot.GatewayBot.dispatch`][]. + Stream : [`hikari.impl.gateway_bot.GatewayBot.stream`][]. + Subscribe : [`hikari.impl.gateway_bot.GatewayBot.subscribe`][]. + Unsubscribe : [`hikari.impl.gateway_bot.GatewayBot.unsubscribe`][]. + Wait_for : [`hikari.impl.gateway_bot.GatewayBot.wait_for`][]. """ return self._event_manager.listen(*event_types) @@ -656,11 +658,11 @@ def print_banner( The package to find a `banner.txt` in. allow_color : bool A flag that allows advising whether to allow color if supported or - not. Can be overridden by setting a `"CLICOLOR"` environment + not. Can be overridden by setting a `CLICOLOR` environment variable to a non-`"0"` string. force_color : bool A flag that allows forcing color to always be output, even if the - terminal device may not support it. Setting the `"CLICOLOR_FORCE"` + terminal device may not support it. Setting the `CLICOLOR_FORCE` environment variable to a non-`"0"` string will override this. This will take precedence over `allow_color` if both are specified. @@ -700,85 +702,85 @@ def run( ---------------- activity : typing.Optional[hikari.presences.Activity] The initial activity to display in the bot user presence, or - `None` (default) to not show any. + [`None`][] (default) to not show any. afk : bool The initial AFK state to display in the bot user presence, or - `False` (default) to not show any. + [`False`][] (default) to not show any. asyncio_debug : bool - Defaults to `False`. If `True`, then debugging is - enabled for the asyncio event loop in use. + If [`True`][], then debugging is enabled for the asyncio event + loop in use. check_for_updates : bool - Defaults to `True`. If `True`, will check for - newer versions of `hikari` on PyPI and notify if available. + If [`True`][], will check for newer versions of hikari on PyPI + and notify if available. close_passed_executor : bool - Defaults to `False`. If `True`, any custom - `concurrent.futures.Executor` passed to the constructor will be - shut down when the application terminates. This does not affect the - default executor associated with the event loop, and will not - do anything if you do not provide a custom executor to the - constructor. + If [`True`][], any custom [`concurrent.futures.Executor`][] passed + to the constructor will be shut down when the application + terminates. This does not affect the default executor associated + with the event loop, and will not do anything if you do not + provide a custom executor to the constructor. close_loop : bool - Defaults to `True`. If `True`, then once the bot - enters a state where all components have shut down permanently - during application shut down, then all asyncgens and background tasks - will be destroyed, and the event loop will be shut down. + If [`True`][], then once the bot enters a state where all components + have shut down permanently during application shut down, then + all asyncgens and background tasks will be destroyed, and the + event loop will be shut down. - This will wait until all `hikari`-owned `aiohttp` connectors have + This will wait until all hikari-owned [`aiohttp`][] connectors have had time to attempt to shut down correctly (around 250ms), and on Python 3.9 and newer, will also shut down the default event loop executor too. coroutine_tracking_depth : typing.Optional[int] - Defaults to `None`. If an integer value and supported by + If an integer value and supported by the interpreter, then this many nested coroutine calls will be tracked with their call origin state. This allows you to determine where non-awaited coroutines may originate from, but generally you do not want to leave this enabled for performance reasons. enable_signal_handlers : typing.Optional[bool] - Defaults to `True` if this is started in the main thread. + Defaults to [`True`][] if this is called in the main thread. If on a non-Windows OS with builtin support for kernel-level - POSIX signals, then setting this to `True` will allow + POSIX signals, then setting this to [`True`][] will allow treating keyboard interrupts and other OS signals to safely shut down the application as calls to shut down the application properly rather than just killing the process in a dirty state immediately. You should leave this enabled unless you plan to implement your own signal handling yourself. idle_since : typing.Optional[datetime.datetime] - The `datetime.datetime` the user should be marked as being idle - since, or `None` (default) to not show this. + The [`datetime.datetime`][] the user should be marked as being idle + since, or [`None`][] to not show this. ignore_session_start_limit : bool - Defaults to `False`. If `False`, then attempting - to start more sessions than you are allowed in a 24 hour window - will throw a `RuntimeError` rather than going ahead - and hitting the IDENTIFY limit, which may result in your token - being reset. Setting to `True` disables this behavior. + If [`False`][], then attempting to start more sessions than + you are allowed in a 24 hour window will throw a [`RuntimeError`][] + rather than going ahead and hitting the IDENTIFY limit, which + may result in your token being reset. Setting to [`True`][] + disables this behavior. large_threshold : int Threshold for members in a guild before it is treated as being - "large" and no longer sending member details in the `GUILD CREATE` - event. Defaults to `250`. + "large" and no longer sending member details in the [GUILD CREATE][] + event. propagate_interrupts : bool - Defaults to `False`. If set to `True`, then any - internal `hikari.errors.HikariInterrupt` that is raises as a - result of catching an OS level signal will result in the - exception being rethrown once the application has closed. This can - allow you to use hikari signal handlers and still be able to - determine what kind of interrupt the application received after - it closes. When `False`, nothing is raised and the call - will terminate cleanly and silently where possible instead. + If [`True`][], then any internal [`hikari.errors.HikariInterrupt`][] + that is raises as a result of catching an OS level signal will + result in the exception being rethrown once the application has + closed. This can allow you to use hikari signal handlers and + still be able to determine what kind of interrupt the + application received after it closes. When [`False`][], nothing + is raised and the call will terminate cleanly and silently + where possible instead. shard_ids : typing.Optional[typing.Sequence[int]] - The shard IDs to create shards for. If not `None`, then - a non-`None` `shard_count` must ALSO be provided. Defaults to - `None`, which means the Discord-recommended count is used - for your application instead. + The shard IDs to create shards for. If not [`None`][], then + a non-[`None`][] `shard_count` must ALSO be provided. + + Defaults to [`None`][], which means the Discord-recommended count + is used for your application instead. Note that the sequence will be de-duplicated. shard_count : typing.Optional[int] The number of shards to use in the entire distributed application. - Defaults to `None` which results in the count being + + Defaults to [`None`][] which results in the count being determined dynamically on startup. status : hikari.presences.Status The initial status to show for the user presence on startup. - Defaults to `hikari.presences.Status.ONLINE`. Raises ------ @@ -866,40 +868,40 @@ async def start( ---------------- activity : typing.Optional[hikari.presences.Activity] The initial activity to display in the bot user presence, or - `None` (default) to not show any. + [`None`][] (default) to not show any. afk : bool The initial AFK state to display in the bot user presence, or - `False` (default) to not show any. + [`False`][] (default) to not show any. check_for_updates : bool - Defaults to `True`. If `True`, will check for + If [`True`][], will check for newer versions of `hikari` on PyPI and notify if available. idle_since : typing.Optional[datetime.datetime] - The `datetime.datetime` the user should be marked as being idle - since, or `None` (default) to not show this. + The [`datetime.datetime`][] the user should be marked as being idle + since, or [`None`][] (default) to not show this. ignore_session_start_limit : bool - Defaults to `False`. If `False`, then attempting - to start more sessions than you are allowed in a 24 hour window - will throw a `RuntimeError` rather than going ahead - and hitting the IDENTIFY limit, which may result in your token - being reset. Setting to `True` disables this behavior. + If [`False`][], then attempting to start more sessions than you + are allowed in a 24 hour window will throw a [`RuntimeError`][] + rather than going ahead and hitting the IDENTIFY limit, + which may result in your token being reset. Setting to [`True`][] + disables this behavior. large_threshold : int Threshold for members in a guild before it is treated as being "large" and no longer sending member details in the `GUILD CREATE` - event. Defaults to `250`. + event. shard_ids : typing.Optional[typing.Sequence[int]] - The shard IDs to create shards for. If not `None`, then - a non-`None` `shard_count` must ALSO be provided. Defaults to - `None`, which means the Discord-recommended count is used + The shard IDs to create shards for. If not [`None`][], then + a non-[`None`][] `shard_count` must ALSO be provided. Defaults to + [`None`][], which means the Discord-recommended count is used for your application instead. Note that the sequence will be de-duplicated. shard_count : typing.Optional[int] The number of shards to use in the entire distributed application. - Defaults to `None` which results in the count being + + Defaults to [`None`][] which results in the count being determined dynamically on startup. status : hikari.presences.Status The initial status to show for the user presence on startup. - Defaults to `hikari.presences.Status.ONLINE`. Raises ------ @@ -1013,7 +1015,7 @@ def stream( ) -> event_manager_.EventStream[base_events.EventT]: """Return a stream iterator for the given event and sub-events. - .. warning:: + !!! warning If you use `stream.open()` to start the stream then you must also close it with `stream.close()` otherwise it may queue events in memory indefinitely. @@ -1025,11 +1027,11 @@ def stream( this type additionally. timeout : typing.Optional[int, float] How long this streamer should wait for the next event before - ending the iteration. If `None` then this will continue + ending the iteration. If [`None`][] then this will continue until explicitly broken from. limit : typing.Optional[int] The limit for how many events this should queue at one time before - dropping extra incoming events, leave this as `None` for + dropping extra incoming events, leave this as [`None`][] for the cache size to be unlimited. Returns @@ -1041,16 +1043,15 @@ def stream( Examples -------- - .. code-block:: python - + ```py with bot.stream(events.ReactionAddEvent, timeout=30).filter(("message_id", message.id)) as stream: async for user_id in stream.map("user_id").limit(50): ... + ``` or using `open()` and `close()` - .. code-block:: python - + ```py stream = bot.stream(events.ReactionAddEvent, timeout=30).filter(("message_id", message.id)) stream.open() @@ -1058,14 +1059,15 @@ def stream( ... stream.close() + ``` See Also -------- - Dispatch : `hikari.impl.gateway_bot.GatewayBot.dispatch`. - Listen : `hikari.impl.gateway_bot.GatewayBot.listen`. - Subscribe : `hikari.impl.gateway_bot.GatewayBot.subscribe`. - Unsubscribe : `hikari.impl.gateway_bot.GatewayBot.unsubscribe`. - Wait_for : `hikari.impl.gateway_bot.GatewayBot.wait_for`. + Dispatch : [`hikari.impl.gateway_bot.GatewayBot.dispatch`][]. + Listen : [`hikari.impl.gateway_bot.GatewayBot.listen`][]. + Subscribe : [`hikari.impl.gateway_bot.GatewayBot.subscribe`][]. + Unsubscribe : [`hikari.impl.gateway_bot.GatewayBot.unsubscribe`][]. + Wait_for : [`hikari.impl.gateway_bot.GatewayBot.wait_for`][]. """ self._check_if_alive() return self._event_manager.stream(event_type, timeout=timeout, limit=limit) @@ -1082,7 +1084,7 @@ def subscribe(self, event_type: typing.Type[typing.Any], callback: event_manager event_type : typing.Type[T] The event type to listen for. This will also listen for any subclasses of the given type. - `T` must be a subclass of `hikari.events.base_events.Event`. + `T` must be a subclass of [`hikari.events.base_events.Event`][]. callback Must be a coroutine function to invoke. This should consume an instance of the given event, or an instance of a valid @@ -1093,22 +1095,22 @@ def subscribe(self, event_type: typing.Type[typing.Any], callback: event_manager The following demonstrates subscribing a callback to message creation events. - .. code-block:: python - + ```py from hikari.events.messages import MessageCreateEvent async def on_message(event): ... bot.subscribe(MessageCreateEvent, on_message) + ``` See Also -------- - Dispatch : `hikari.impl.gateway_bot.GatewayBot.dispatch`. - Listen : `hikari.impl.gateway_bot.GatewayBot.listen`. - Stream : `hikari.impl.gateway_bot.GatewayBot.stream`. - Unsubscribe : `hikari.impl.gateway_bot.GatewayBot.unsubscribe`. - Wait_for : `hikari.impl.gateway_bot.GatewayBot.wait_for`. + Dispatch : [`hikari.impl.gateway_bot.GatewayBot.dispatch`][]. + Listen : [`hikari.impl.gateway_bot.GatewayBot.listen`][]. + Stream : [`hikari.impl.gateway_bot.GatewayBot.stream`][]. + Unsubscribe : [`hikari.impl.gateway_bot.GatewayBot.unsubscribe`][]. + Wait_for : [`hikari.impl.gateway_bot.GatewayBot.wait_for`][]. """ self._event_manager.subscribe(event_type, callback) @@ -1124,7 +1126,7 @@ def unsubscribe(self, event_type: typing.Type[typing.Any], callback: event_manag event_type : typing.Type[T] The event type to unsubscribe from. This must be the same exact type as was originally subscribed with to be removed correctly. - `T` must derive from `hikari.events.base_events.Event`. + `T` must derive from [`hikari.events.base_events.Event`][]. callback The callback to unsubscribe. @@ -1133,22 +1135,22 @@ def unsubscribe(self, event_type: typing.Type[typing.Any], callback: event_manag The following demonstrates unsubscribing a callback from a message creation event. - .. code-block:: python - + ```py from hikari.events.messages import MessageCreateEvent async def on_message(event): ... bot.unsubscribe(MessageCreateEvent, on_message) + ``` See Also -------- - Dispatch : `hikari.impl.gateway_bot.GatewayBot.dispatch`. - Listen : `hikari.impl.gateway_bot.GatewayBot.listen`. - Stream : `hikari.impl.gateway_bot.GatewayBot.stream`. - Subscribe : `hikari.impl.gateway_bot.GatewayBot.subscribe`. - Wait_for : `hikari.impl.gateway_bot.GatewayBot.wait_for`. + Dispatch : [`hikari.impl.gateway_bot.GatewayBot.dispatch`][]. + Listen : [`hikari.impl.gateway_bot.GatewayBot.listen`][]. + Stream : [`hikari.impl.gateway_bot.GatewayBot.stream`][]. + Subscribe : [`hikari.impl.gateway_bot.GatewayBot.subscribe`][]. + Wait_for : [`hikari.impl.gateway_bot.GatewayBot.wait_for`][]. """ self._event_manager.unsubscribe(event_type, callback) @@ -1161,7 +1163,7 @@ async def wait_for( ) -> base_events.EventT: """Wait for a given event to occur once, then return the event. - .. warning:: + !!! warning Async predicates are not supported. Parameters @@ -1171,14 +1173,14 @@ async def wait_for( this type additionally. predicate A function taking the event as the single parameter. - This should return `True` if the event is one you want to - return, or `False` if the event should not be returned. - If left as `None` (the default), then the first matching event type + This should return [`True`][] if the event is one you want to + return, or [`False`][] if the event should not be returned. + If left as [`None`][] (the default), then the first matching event type that the bot receives (or any subtype) will be the one returned. timeout : typing.Union[float, int, None] - The amount of time to wait before raising an `asyncio.TimeoutError` + The amount of time to wait before raising an [`asyncio.TimeoutError`][] and giving up instead. This is measured in seconds. If - `None`, then no timeout will be waited for (no timeout can + [`None`][], then no timeout will be waited for (no timeout can result in "leaking" of coroutines that never complete if called in an uncontrolled way, so is not recommended). @@ -1190,16 +1192,16 @@ async def wait_for( Raises ------ asyncio.TimeoutError - If the timeout is not `None` and is reached before an - event is received that the predicate returns `True` for. + If the timeout is not [`None`][] and is reached before an + event is received that the predicate returns [`True`][] for. See Also -------- - Dispatch : `hikari.impl.gateway_bot.GatewayBot.dispatch`. - Listen : `hikari.impl.gateway_bot.GatewayBot.listen`. - Stream : `hikari.impl.gateway_bot.GatewayBot.stream`. - Subscribe : `hikari.impl.gateway_bot.GatewayBot.subscribe`. - Unsubscribe : `hikari.impl.gateway_bot.GatewayBot.unsubscribe`. + Dispatch : [`hikari.impl.gateway_bot.GatewayBot.dispatch`][]. + Listen : [`hikari.impl.gateway_bot.GatewayBot.listen`][]. + Stream : [`hikari.impl.gateway_bot.GatewayBot.stream`][]. + Subscribe : [`hikari.impl.gateway_bot.GatewayBot.subscribe`][]. + Unsubscribe : [`hikari.impl.gateway_bot.GatewayBot.unsubscribe`][]. """ self._check_if_alive() return await self._event_manager.wait_for(event_type, timeout=timeout, predicate=predicate) diff --git a/hikari/impl/interaction_server.py b/hikari/impl/interaction_server.py index cd4b5aa6f0..e7a15caa55 100644 --- a/hikari/impl/interaction_server.py +++ b/hikari/impl/interaction_server.py @@ -180,7 +180,7 @@ async def _consume_generator_listener(generator: typing.AsyncGenerator[typing.An class InteractionServer(interaction_server.InteractionServer): - """Standard implementation of `hikari.api.interaction_server.InteractionServer`. + """Standard implementation of [`hikari.api.interaction_server.InteractionServer`][]. Parameters ---------- @@ -190,12 +190,12 @@ class InteractionServer(interaction_server.InteractionServer): Other Parameters ---------------- dumps : hikari.internal.data_binding.JSONEncoder - The JSON encoder this server should use. Defaults to `hikari.internal.data_binding.default_json_dumps`. + The JSON encoder this server should use. loads : hikari.internal.data_binding.JSONDecoder - The JSON decoder this server should use. Defaults to `hikari.internal.data_binding.default_json_loads`. - public_key : bytes + The JSON decoder this server should use. + public_key : typing.Optional[bytes] The public key this server should use for verifying request payloads from - Discord. If left as `None` then the client will try to work this + Discord. If left as [`None`][] then the client will try to work this out using `rest_client`. rest_client : hikari.api.rest.RESTClient The client this should use for making REST requests. @@ -280,7 +280,7 @@ async def aiohttp_hook(self, request: aiohttp.web.Request) -> aiohttp.web.Respon """Handle an AIOHTTP interaction request. This method handles aiohttp specific detail before calling - `InteractionServer.on_interaction` with the data extracted from the + [`hikari.impl.interaction_server.InteractionServer.on_interaction`][] with the data extracted from the request if it can and handles building an aiohttp response. Parameters @@ -399,7 +399,7 @@ async def join(self) -> None: async def on_interaction(self, body: bytes, signature: bytes, timestamp: bytes) -> interaction_server.Response: """Handle an interaction received from Discord as a REST server. - .. note:: + !!! note If this server instance is alive then this will be called internally by the server but if the instance isn't alive then this may still be called externally to trigger interaction dispatch. @@ -502,7 +502,7 @@ async def start( ) -> None: """Start the bot and wait for the internal server to startup then return. - .. note:: + !!! note For more information on the other parameters such as defaults see AIOHTTP's documentation. @@ -526,8 +526,8 @@ async def start( socket : typing.Optional[socket.socket] A pre-existing socket object to accept connections on. shutdown_timeout : float - A delay to wait for graceful server shutdown before forcefully - disconnecting all open client sockets. This defaults to 60 seconds. + A delay to wait, in seconds, for graceful server shutdown + before forcefully disconnecting all open client sockets. ssl_context : typing.Optional[ssl.SSLContext] SSL context for HTTPS servers. """ diff --git a/hikari/impl/rate_limits.py b/hikari/impl/rate_limits.py index ac4a92856d..8899c712a6 100644 --- a/hikari/impl/rate_limits.py +++ b/hikari/impl/rate_limits.py @@ -22,7 +22,7 @@ # SOFTWARE. """Basic lazy ratelimit systems for asyncio. -See `hikari.impl.buckets` for HTTP-specific rate-limiting logic. +See [`hikari.impl.buckets`][] for HTTP-specific rate-limiting logic. """ from __future__ import annotations @@ -92,7 +92,7 @@ class BurstRateLimiter(BaseRateLimiter, abc.ABC): """The name of the rate limiter.""" throttle_task: typing.Optional[asyncio.Task[typing.Any]] - """The throttling task, or `None` if it is not running.""" + """The throttling task, or [`None`][] if it is not running.""" queue: typing.List[asyncio.Future[typing.Any]] """The queue of any futures under a rate limit.""" @@ -130,7 +130,7 @@ def close(self) -> None: @property def is_empty(self) -> bool: - """Return `True` if no futures are on the queue being rate limited.""" + """Return [`True`][] if no futures are on the queue being rate limited.""" return len(self.queue) == 0 @@ -139,11 +139,11 @@ class ManualRateLimiter(BurstRateLimiter): """Rate limit handler for the global HTTP rate limit. This is a non-preemptive rate limiting algorithm that will always return - completed futures until `ManualRateLimiter.throttle` is invoked. Once this - is invoked, any subsequent calls to `ManualRateLimiter.acquire` will return + completed futures until [`hikari.impl.rate_limits.ManualRateLimiter.throttle`][] is invoked. Once this + is invoked, any subsequent calls to [`hikari.impl.rate_limits.ManualRateLimiter.acquire`][] will return incomplete futures that will be enqueued to an internal queue. A task will be spun up to wait for a period of time given to the - `ManualRateLimiter.throttle`. Once that has passed, the lock will begin to + [`hikari.impl.rate_limits.ManualRateLimiter.throttle`][]. Once that has passed, the lock will begin to re-consume incomplete futures on the queue, completing them. Triggering a throttle when it is already set will cancel the current @@ -161,7 +161,7 @@ class ManualRateLimiter(BurstRateLimiter): # <>. reset_at: typing.Optional[float] - """The monotonic `time.monotonic` timestamp at which the ratelimit gets lifted.""" + """The monotonic [`time.monotonic`][] timestamp at which the ratelimit gets lifted.""" def __init__(self) -> None: super().__init__("global") @@ -187,16 +187,16 @@ def throttle(self, retry_after: float) -> None: """Perform the throttling rate limiter logic. Iterates repeatedly while the queue is not empty, adhering to any - rate limits that occur in the mean time. + rate limits that occur in the meantime. - .. note:: - This will invoke `ManualRateLimiter.unlock_later` as a scheduled + !!! note + This will invoke [`hikari.impl.rate_limits.ManualRateLimiter.unlock_later`][] as a scheduled task in the future (it will not await it to finish). - When the `ManualRateLimiter.unlock_later` coroutine function + When the [`hikari.impl.rate_limits.ManualRateLimiter.unlock_later`][] coroutine function completes, it should be expected to set the `throttle_task` to - `None`. This means you can check if throttling is occurring - by checking if `throttle_task` is not `None`. + [`None`][]. This means you can check if throttling is occurring + by checking if `throttle_task` is not [`None`][]. If this is invoked while another throttle is in progress, that one is cancelled and a new one is started. This enables new rate limits @@ -217,14 +217,14 @@ def throttle(self, retry_after: float) -> None: async def unlock_later(self, retry_after: float) -> None: """Sleep for a while, then remove the lock. - .. warning:: + !!! warning You should not need to invoke this directly. Call - `ManualRateLimiter.throttle` instead. + [`hikari.impl.rate_limits.ManualRateLimiter.throttle`][] instead. - When the `ManualRateLimiter.unlock_later` coroutine function + When the [`hikari.impl.rate_limits.ManualRateLimiter.unlock_later`][] coroutine function completes, it should be expected to set the `throttle_task` to - `None`. This means you can check if throttling is occurring - by checking if `throttle_task` is not `None`. + [`None`][]. This means you can check if throttling is occurring + by checking if `throttle_task` is not [`None`][]. Parameters ---------- @@ -249,7 +249,7 @@ def get_time_until_reset(self, now: float) -> float: Parameters ---------- now : float - The monotonic `time.monotonic` timestamp. + The monotonic [`time.monotonic`][] timestamp. Returns ------- @@ -269,7 +269,7 @@ class WindowedBurstRateLimiter(BurstRateLimiter): Rate limiter for rate limits that last fixed periods of time with a fixed number of times it can be used in that time frame. - To use this, you should call `WindowedBurstRateLimiter.acquire` and await the + To use this, you should call [`hikari.impl.rate_limits.WindowedBurstRateLimiter.acquire`][] and await the result immediately before performing your rate-limited task. If the rate limit has been hit, acquiring time will return an incomplete @@ -298,16 +298,18 @@ class WindowedBurstRateLimiter(BurstRateLimiter): # <>. reset_at: float - """The `time.monotonic` that the limit window ends at.""" + """The [`time.monotonic`][] that the limit window ends at.""" remaining: int - """The number of `WindowedBurstRateLimiter.acquire`'s left in this window before you will get rate limited.""" + """The number of [`hikari.impl.rate_limits.WindowedBurstRateLimiter.acquire`][]'s + left in this window before you will get rate limited.""" period: float """How long the window lasts for from the start in seconds.""" limit: int - """The maximum number of `WindowedBurstRateLimiter.acquire`'s allowed in this time window.""" + """The maximum number of [`hikari.impl.rate_limits.WindowedBurstRateLimiter.acquire`][]'s + allowed in this time window.""" def __init__(self, name: str, period: float, limit: int) -> None: super().__init__(name) @@ -341,7 +343,7 @@ async def acquire(self) -> None: def get_time_until_reset(self, now: float) -> float: """Determine how long until the current rate limit is reset. - .. warning:: + !!! warning Invoking this method will update the internal state if we were previously rate limited, but at the given time are no longer under that limit. This makes it imperative that you only pass the current @@ -351,7 +353,7 @@ def get_time_until_reset(self, now: float) -> float: Parameters ---------- now : float - The monotonic `time.monotonic` timestamp. + The monotonic [`time.monotonic`][] timestamp. Returns ------- @@ -366,7 +368,7 @@ def get_time_until_reset(self, now: float) -> float: def is_rate_limited(self, now: float) -> bool: """Determine if we are under a rate limit at the given time. - .. warning:: + !!! warning Invoking this method will update the internal state if we were previously rate limited, but at the given time are no longer under that limit. This makes it imperative that you only pass the current @@ -376,13 +378,12 @@ def is_rate_limited(self, now: float) -> bool: Parameters ---------- now : float - The monotonic `time.monotonic` timestamp. + The monotonic [`time.monotonic`][] timestamp. Returns ------- bool - `True` if we are being rate limited, or `False` if - we are not. + Whether the bucket is ratelimited. """ if self.reset_at <= now: self.remaining = self.limit @@ -401,14 +402,16 @@ async def throttle(self) -> None: Iterates repeatedly while the queue is not empty, adhering to any rate limits that occur in the mean time. - .. note:: + !!! note You should usually not need to invoke this directly, but if you do, - ensure to call it using `asyncio.create_task`, and store the - task immediately in `throttle_task`. + ensure to call it using [`asyncio.create_task`][], and store the + task immediately in + [`hikari.impl.rate_limits.WindowedBurstRateLimiter.throttle_task`][]. When this coroutine function completes, it will set the - `throttle_task` to `None`. This means you can check if throttling - is occurring by checking if `throttle_task` is not `None`. + [`hikari.impl.rate_limits.WindowedBurstRateLimiter.throttle_task`][] + to [`None`][]. This means you can check if throttling + is occurring by checking if it is not [`None`][]. """ while self.queue: sleep_for = self.get_time_until_reset(time.monotonic()) @@ -428,51 +431,47 @@ async def throttle(self) -> None: class ExponentialBackOff: r"""Implementation of an asyncio-compatible exponential back-off algorithm with random jitter. - $t_{backoff} = b^{i} + m \cdot \mathrm{rand}()$ - - Such that $\(t_{backoff}\)$ is the backoff time, $\(b\)$ is the base, - $\(i\)$ is the increment that increases by 1 for each invocation, and - $\(m\)$ is the jitter multiplier. $\(\mathrm{rand}()\)$ returns a value in - the range $\([0,1]\)$. + Each backoff will be calculated by raising the `base` to the increment + (the number of invocations since last reset) and added on to it, the + jitter, calculated as `jitter_multiplier` times a random number between + 0 and 1. Parameters ---------- base : float - The base to use. Defaults to `2.0`. + The base to use. maximum : float The max value the backoff can be in a single iteration. All values will be capped to this base value plus some random jitter. jitter_multiplier : float - The multiplier for the random jitter. Defaults to `1.0`. + The multiplier for the random jitter. + Set to `0` to disable jitter. initial_increment : int - The initial increment to start at. Defaults to `0`. + The initial increment to start at. Raises ------ ValueError - If an `int` that's too big to be represented as a - `float` or a non-finite value is passed in place of a field - that's annotated as `float`. + If an [`int`][] that's too big to be represented as a + [`float`][] or a non-finite value is passed in place of a field + that's annotated as [`float`][]. """ __slots__: typing.Sequence[str] = ("base", "increment", "maximum", "jitter_multiplier") base: typing.Final[float] - """The base to use. Defaults to 2.0.""" + """The base to use.""" increment: int """The current increment.""" maximum: float - """This is the max value the backoff can be in a single iteration before an `asyncio.TimeoutError` is raised.""" + """This is the max value the backoff can be in a single iteration before an [`asyncio.TimeoutError`][] is raised.""" jitter_multiplier: typing.Final[float] - """The multiplier for the random jitter. - - This defaults to `1.0`. Set to `0.0` to disable jitter. - """ + """The multiplier for the random jitter.""" def __init__( self, base: float = 2.0, maximum: float = 64.0, jitter_multiplier: float = 1.0, initial_increment: int = 0 diff --git a/hikari/impl/rest.py b/hikari/impl/rest.py index f2957c63a5..f7320e10fc 100644 --- a/hikari/impl/rest.py +++ b/hikari/impl/rest.py @@ -252,26 +252,26 @@ class RESTApp(traits.ExecutorAware): """The base for a HTTP-only Discord application. This comprises of a shared TCP connector connection pool, and can have - `RESTClientImpl` instances for specific credentials acquired + [`hikari.impl.rest.RESTClientImpl`][] instances for specific credentials acquired from it. Parameters ---------- executor : typing.Optional[concurrent.futures.Executor] - The executor to use for blocking file IO operations. If `None` - is passed, then the default `concurrent.futures.ThreadPoolExecutor` for - the `asyncio.AbstractEventLoop` will be used instead. + The executor to use for blocking file IO operations. If [`None`][] + is passed, then the default [`concurrent.futures.ThreadPoolExecutor`][] for + the [`asyncio.AbstractEventLoop`][] will be used instead. http_settings : typing.Optional[hikari.impl.config.HTTPSettings] HTTP settings to use. Sane defaults are used if this is - `None`. + [`None`][]. dumps : hikari.internal.data_binding.JSONEncoder - The JSON encoder this application should use. Defaults to `hikari.internal.data_binding.default_json_dumps`. + The JSON encoder this application should use. loads : hikari.internal.data_binding.JSONDecoder - The JSON decoder this application should use. Defaults to `hikari.internal.data_binding.default_json_loads`. + The JSON decoder this application should use. max_rate_limit : float Maximum number of seconds to sleep for when rate limited. If a rate limit occurs that is longer than this value, then a - `hikari.errors.RateLimitTooLongError` will be raised instead of waiting. + [`hikari.errors.RateLimitTooLongError`][] will be raised instead of waiting. This is provided since some endpoints may respond with non-sensible rate limits. @@ -279,13 +279,15 @@ class RESTApp(traits.ExecutorAware): Defaults to five minutes if unspecified. max_retries : typing.Optional[int] Maximum number of times a request will be retried if - it fails with a `5xx` status. Defaults to 3 if set to `None`. + it fails with a `5xx` status. + + Defaults to 3 if set to [`None`][]. proxy_settings : typing.Optional[hikari.impl.config.ProxySettings] - Proxy settings to use. If `None` then no proxy configuration + Proxy settings to use. If [`None`][] then no proxy configuration will be used. url : typing.Optional[str] The base URL for the API. You can generally leave this as being - `None` and the correct default API base URL will be generated. + [`None`][] and the correct default API base URL will be generated. """ __slots__: typing.Sequence[str] = ( @@ -369,15 +371,14 @@ def acquire( ) -> RESTClientImpl: """Acquire an instance of this REST client. - .. note:: + !!! note The returned REST client should be started before it can be used, - either by calling `RESTClientImpl.start` or by using it as an + either by calling [`hikari.impl.rest.RESTClientImpl.start`][] or by using it as an asynchronous context manager. Examples -------- - .. code-block:: python - + ```py rest_app = RESTApp() await rest_app.start() @@ -387,6 +388,7 @@ def acquire( user = await client.fetch_my_user() await rest_app.close() + ``` Parameters ---------- @@ -394,12 +396,12 @@ def acquire( The bot or bearer token. If no token is to be used, this can be undefined. token_type : typing.Union[str, hikari.applications.TokenType, None] - The type of token in use. This should only be passed when `str` + The type of token in use. This should only be passed when [`str`][] is passed for `token`, can be `"Bot"` or `"Bearer"` and will be defaulted to `"Bearer"` in this situation. - This should be left as `None` when either - `hikari.api.rest.TokenStrategy` or `None` is passed for + This should be left as [`None`][] when either + [`hikari.api.rest.TokenStrategy`][] or [`None`][] is passed for `token`. Returns @@ -490,24 +492,27 @@ class RESTClientImpl(rest_api.RESTClient): entity_factory : hikari.api.entity_factory.EntityFactory The entity factory to use. executor : typing.Optional[concurrent.futures.Executor] - The executor to use for blocking IO. Defaults to the `asyncio` thread - pool if set to `None`. + The executor to use for blocking IO. + + Defaults to the [`asyncio`][] thread pool if set to [`None`][]. max_retries : typing.Optional[int] Maximum number of times a request will be retried if - it fails with a `5xx` status. Defaults to 3 if set to `None`. + it fails with a `5xx` status. + + Defaults to 3 if set to [`None`][]. dumps : hikari.internal.data_binding.JSONEncoder - The JSON encoder this application should use. Defaults to `hikari.internal.data_binding.default_json_dumps`. + The JSON encoder this application should use. loads : hikari.internal.data_binding.JSONDecoder - The JSON decoder this application should use. Defaults to `hikari.internal.data_binding.default_json_loads`. + The JSON decoder this application should use. token : typing.Union[str, None, hikari.api.rest.TokenStrategy] The bot or bearer token. If no token is to be used, this can be undefined. token_type : typing.Union[str, hikari.applications.TokenType, None] - The type of token in use. This must be passed when a `str` is + The type of token in use. This must be passed when a [`str`][] is passed for `token` but and can be `"Bot"` or `"Bearer"`. - This should be left as `None` when either - `hikari.api.rest.TokenStrategy` or `None` is passed for + This should be left as [`None`][] when either + [`hikari.api.rest.TokenStrategy`][] or [`None`][] is passed for `token`. rest_url : str The HTTP API base URL. This can contain format-string specifiers to @@ -517,7 +522,7 @@ class RESTClientImpl(rest_api.RESTClient): ------ ValueError If `token_type` is provided when a token strategy is passed for `token`, if - `token_type` is left as `None` when a string is passed for `token` or if a + `token_type` is left as [`None`][] when a string is passed for `token` or if a value greater than 5 is provided for `max_retries`. """ @@ -646,7 +651,7 @@ async def close(self) -> None: def start(self) -> None: """Start the HTTP client. - .. note:: + !!! note This must be called within an active event loop. Raises diff --git a/hikari/impl/rest_bot.py b/hikari/impl/rest_bot.py index f44d9de442..c768529634 100644 --- a/hikari/impl/rest_bot.py +++ b/hikari/impl/rest_bot.py @@ -73,18 +73,17 @@ class RESTBot(traits.RESTBotAware, interaction_server_.InteractionServer): token : typing.Union[str, hikari.api.rest.TokenStrategy] The bot or bearer token. token_type : typing.Union[str, hikari.applications.TokenType, None] - The type of token in use. This should only be passed when `str` + The type of token in use. This should only be passed when [`str`][] is passed for `token`, can be `"Bot"` or `"Bearer"` and defaults to `"Bot". - This should be left as `None` when `hikari.api.rest.TokenStrategy` - is passed for `token`. + This should be left as [`None`][] when [`hikari.api.rest.TokenStrategy`][] + is passed for [`token`][]. Other Parameters ---------------- allow_color : bool - Defaulting to `True`, this will enable coloured console logs - on any platform that is a TTY. + Whether to enable coloured console logs on any platform that is a TTY. Setting a `"CLICOLOR"` environment variable to any **non `0`** value will override this setting. @@ -94,60 +93,58 @@ class RESTBot(traits.RESTBotAware, interaction_server_.InteractionServer): explicitly disable this is provided. See `force_color` for an alternative. banner : typing.Optional[str] - The package to search for a `banner.txt` in. Defaults to `"hikari"` for - the `"hikari/banner.txt"` banner. - Setting this to `None` will disable the banner being shown. + The package to search for a `banner.txt` in. + + Setting this to [`None`][] will disable the banner being shown. suppress_optimization_warning : bool - Defaults to `False`. By default, Hikari warns you if you are not running - your bot using optimizations (`-O` or `-OO`). If this is `True`, you won't - receive these warnings, even if you are not running using optimizations. + By default, Hikari warns you if you are not running your bot using + optimizations (`-O` or `-OO`). If this is [`True`][], you won't receive + these warnings, even if you are not running using optimizations. executor : typing.Optional[concurrent.futures.Executor] - Defaults to `None`. If non-`None`, then this executor - is used instead of the `concurrent.futures.ThreadPoolExecutor` attached - to the `asyncio.AbstractEventLoop` that the bot will run on. This + If non-[`None`][], then this executor is used instead of the + [`concurrent.futures.ThreadPoolExecutor`][] attached to the + [`asyncio.AbstractEventLoop`][] that the bot will run on. This executor is used primarily for file-IO. - While mainly supporting the `concurrent.futures.ThreadPoolExecutor` - implementation in the standard lib, Hikari's file handling systems - should also work with `concurrent.futures.ProcessPoolExecutor`, which + While mainly supporting the [`concurrent.futures.ThreadPoolExecutor`][] + implementation in the standard lib, hikari's file handling systems + should also work with [`concurrent.futures.ProcessPoolExecutor`][], which relies on all objects used in IPC to be pickleable. Many third-party libraries will not support this fully though, so your mileage may vary on using ProcessPoolExecutor implementations with this parameter. force_color : bool - Defaults to `False`. If `True`, then this application - will __force__ colour to be used in console-based output. Specifying a - `"CLICOLOR_FORCE"` environment variable with a non-`"0"` value will + If [`True`][], then this application will __force__ colour to be + used in console-based output. Specifying a `"CLICOLOR_FORCE"` + environment variable with a non-`"0"` value will override this setting. This will take precedence over `allow_color` if both are specified. http_settings : typing.Optional[hikari.config.HTTPSettings] Optional custom HTTP configuration settings to use. Allows you to customise functionality such as whether SSL-verification is enabled, - what timeouts `aiohttp` should expect to use for requests, and behavior + what timeouts [`aiohttp`][] should expect to use for requests, and behavior regarding HTTP-redirects. logs : typing.Union[None, int, str, typing.Dict[str, typing.Any], os.PathLike[str]] The flavour to set the logging to. - This can be `None` to not enable logging automatically. + This can be [`None`][] to not enable logging automatically. - If you pass a `str` or a `int`, it is interpreted as + If you pass a [`str`][] or a [`int`][], it is interpreted as the global logging level to use, and should match one of `"DEBUG"`, `"INFO"`, `"WARNING"`, `"ERROR"` or `"CRITICAL"`. The configuration will be set up to use a `colorlog` coloured logger, and to use a sane logging format strategy. The output will be written - to `sys.stdout` using this configuration. + to [`sys.stdout`][] using this configuration. - If you pass a `dict`, it is treated as the mapping to pass to - `logging.config.dictConfig`. If the dict defines any handlers, default + If you pass a [`dict`][], it is treated as the mapping to pass to + [`logging.config.dictConfig`][]. If the dict defines any handlers, default handlers will not be setup if `incremental` is not specified. - If you pass a `str` to an existing file or a `os.PathLike`, it is - interpreted as the file to load config from using `logging.config.fileConfig`. + If you pass a [`str`][] to an existing file or a [`os.PathLike`][], it is + interpreted as the file to load config from using [`logging.config.fileConfig`][]. Note that `"TRACE_HIKARI"` is a library-specific logging level which is expected to be more verbose than `"DEBUG"`. - - Defaults to `"INFO"`. max_rate_limit : float The max number of seconds to backoff for when rate limited. Anything greater than this will instead raise an error. @@ -163,17 +160,19 @@ class RESTBot(traits.RESTBotAware, interaction_server_.InteractionServer): that may be in use. max_retries : typing.Optional[int] Maximum number of times a request will be retried if - it fails with a `5xx` status. Defaults to 3 if set to `None`. + it fails with a `5xx` status. + + Defaults to 3 if set to [`None`][]. proxy_settings : typing.Optional[hikari.impl.config.ProxySettings] Custom proxy settings to use with network-layer logic in your application to get through an HTTP-proxy. public_key : typing.Union[str, bytes, None] The public key to use to verify received interaction requests. - This may be a hex encoded `str` or the raw `bytes`. - If left as `None` then the client will try to work this value - out based on `token`. + This may be a hex encoded [`str`][] or the raw [`bytes`][]. + If left as [`None`][] then the client will try to work this value + out based on [`token`][]. rest_url : typing.Optional[str] - Defaults to the Discord REST API URL if `None`. Can be + Defaults to the Discord REST API URL if [`None`][]. Can be overridden if you are attempting to point to an unofficial endpoint, or if you are attempting to mock/stub the Discord API for any reason. Generally you do not want to change this. @@ -182,29 +181,28 @@ class RESTBot(traits.RESTBotAware, interaction_server_.InteractionServer): ------ ValueError * If `token_type` is provided when a token strategy is passed for `token`. - * if `token_type` is left as `None` when a string is passed for `token`. + * if `token_type` is left as [`None`][] when a string is passed for `token`. Examples -------- Simple logging setup: - .. code-block:: python - + ```py hikari.RESTBot("TOKEN", logs="INFO") # Registered logging level # or hikari.RESTBot("TOKEN", logs=20) # Logging level as an int + ``` File config: - .. code-block:: python - + ```py # See https://docs.python.org/3/library/logging.config.html#configuration-file-format for more info hikari.RESTBot("TOKEN", logs="path/to/file.ini") + ``` Setting up logging through a dict config: - .. code-block:: python - + ```py # See https://docs.python.org/3/library/logging.config.html#dictionary-schema-details for more info hikari.RESTBot( "TOKEN", @@ -217,6 +215,7 @@ class RESTBot(traits.RESTBotAware, interaction_server_.InteractionServer): }, } ) + ``` """ __slots__: typing.Sequence[str] = ( @@ -394,11 +393,11 @@ def print_banner( The package to find a `banner.txt` in. allow_color : bool A flag that allows advising whether to allow color if supported or - not. Can be overridden by setting a `"CLICOLOR"` environment + not. Can be overridden by setting a `CLICOLOR` environment variable to a non-`"0"` string. force_color : bool A flag that allows forcing color to always be output, even if the - terminal device may not support it. Setting the `"CLICOLOR_FORCE"` + terminal device may not support it. Setting the `CLICOLOR_FORCE` environment variable to a non-`"0"` string will override this. This will take precedence over `allow_color` if both are specified. @@ -491,42 +490,40 @@ def run( Other Parameters ---------------- asyncio_debug : bool - Defaults to `False`. If `True`, then debugging is - enabled for the asyncio event loop in use. + If [`True`][], then debugging is enabled for the asyncio event loop in use. backlog : int The number of unaccepted connections that the system will allow before refusing new connections. check_for_updates : bool - Defaults to `True`. If `True`, will check for - newer versions of `hikari` on PyPI and notify if available. + If [`True`][], will check for newer versions of hikari on + PyPI and notify if available. close_loop : bool - Defaults to `True`. If `True`, then once the bot - enters a state where all components have shut down permanently - during application shut down, then all asyncgens and background tasks - will be destroyed, and the event loop will be shut down. + If [`True`][], then once the bot enters a state where all components + have shut down permanently during application shut down, then all + asyncgens and background tasks will be destroyed, and the event + loop will be shut down. - This will wait until all `hikari`-owned `aiohttp` connectors have + This will wait until all hikari-owned [`aiohttp`][] connectors have had time to attempt to shut down correctly (around 250ms), and on Python 3.9 and newer, will also shut down the default event loop executor too. close_passed_executor : bool - Defaults to `False`. If `True`, any custom - `concurrent.futures.Executor` passed to the constructor will be - shut down when the application terminates. This does not affect the - default executor associated with the event loop, and will not - do anything if you do not provide a custom executor to the - constructor. + If [`True`][], any custom [`concurrent.futures.Executor`][] passed + to the constructor will be shut down when the application + terminates. This does not affect the default executor associated + with the event loop, and will not do anything if you do not + provide a custom executor to the constructor. coroutine_tracking_depth : typing.Optional[int] - Defaults to `None`. If an integer value and supported by - the interpreter, then this many nested coroutine calls will be - tracked with their call origin state. This allows you to determine - where non-awaited coroutines may originate from, but generally you + If an integer value and supported by the interpreter, then this + many nested coroutine calls will be tracked with their call + origin state. This allows you to determine where non-awaited + coroutines may originate from, but generally you do not want to leave this enabled for performance reasons. enable_signal_handlers : typing.Optional[bool] - Defaults to `True` if this is started in the main thread. + Defaults to [`True`][] if this is called in the main thread. If on a non-Windows OS with builtin support for kernel-level - POSIX signals, then setting this to `True` will allow + POSIX signals, then setting this to [`True`][] will allow treating keyboard interrupts and other OS signals to safely shut down the application as calls to shut down the application properly rather than just killing the process in a dirty state immediately. @@ -547,8 +544,8 @@ def run( socket : typing.Optional[socket.socket] A pre-existing socket object to accept connections on. shutdown_timeout : float - A delay to wait for graceful server shut down before forcefully - disconnecting all open client sockets. This defaults to 60 seconds. + A delay, in seconds, to wait for graceful server shut down before forcefully + disconnecting all open client sockets. ssl_context : typing.Optional[ssl.SSLContext] SSL context for HTTPS servers. """ @@ -623,7 +620,7 @@ async def start( ) -> None: """Start the bot and wait for the internal server to startup then return. - .. note:: + !!! note For more information on the other parameters such as defaults see AIOHTTP's documentation. @@ -633,8 +630,8 @@ async def start( The number of unaccepted connections that the system will allow before refusing new connections. check_for_updates : bool - Defaults to `True`. If `True`, will check for - newer versions of `hikari` on PyPI and notify if available. + If [`True`][], will check for newer versions of hikari on PyPI + and notify if available. host : typing.Optional[typing.Union[str, aiohttp.web.HostSequence]] TCP/IP host or a sequence of hosts for the HTTP server. port : typing.Optional[int] @@ -650,8 +647,8 @@ async def start( socket : typing.Optional[socket.socket] A pre-existing socket object to accept connections on. shutdown_timeout : float - A delay to wait for graceful server shut down before forcefully - disconnecting all open client sockets. This defaults to 60 seconds. + A delay, in seconds, to wait for graceful server shut down before forcefully + disconnecting all open client sockets. ssl_context : typing.Optional[ssl.SSLContext] SSL context for HTTPS servers. """ diff --git a/hikari/impl/shard.py b/hikari/impl/shard.py index 112966a750..770de096d9 100644 --- a/hikari/impl/shard.py +++ b/hikari/impl/shard.py @@ -371,7 +371,7 @@ def _serialize_activity(activity: typing.Optional[presences.Activity]) -> data_b class GatewayShardImpl(shard.GatewayShard): """Implementation of a V10 compatible gateway. - .. note:: + !!! note If all four of `initial_activity`, `initial_idle_since`, `initial_is_afk`, and `initial_status` are not defined and left to their default values, then the presence will not be _updated_ on startup @@ -398,24 +398,22 @@ class GatewayShardImpl(shard.GatewayShard): ---------------- compression : typing.Optional[str] Compression format to use for the shard. Only supported values are - `"transport_zlib_stream"` or `None` to disable it. + `"transport_zlib_stream"` or [`None`][] to disable it. dumps : hikari.internal.data_binding.JSONEncoder - The JSON encoder this application should use. Defaults to `hikari.internal.data_binding.default_json_dumps`. + The JSON encoder this application should use. loads : hikari.internal.data_binding.JSONDecoder - The JSON decoder this application should use. Defaults to `hikari.internal.data_binding.default_json_loads`. + The JSON decoder this application should use. initial_activity : typing.Optional[hikari.presences.Activity] The initial activity to appear to have for this shard, or - `None` if no activity should be set initially. This is the + [`None`][] if no activity should be set initially. This is the default. initial_idle_since : typing.Optional[datetime.datetime] - The datetime to appear to be idle since, or `None` if the - shard should not provide this. The default is `None`. + The datetime to appear to be idle since, or [`None`][] if the + shard should not provide this. The default is [`None`][]. initial_is_afk : bool - Whether to appear to be AFK or not on login. Defaults to - `False`. + Whether to appear to be AFK or not on login. initial_status : hikari.presences.Status - The initial status to set on login for the shard. Defaults to - `hikari.presences.Status.ONLINE`. + The initial status to set on login for the shard. intents : hikari.intents.Intents Collection of intents to use. large_threshold : int @@ -776,7 +774,7 @@ async def _poll_events(self) -> None: return elif op == _INVALID_SESSION: - can_reconnect = payload[_D] # We can resume if the payload data is `true`. + can_reconnect = payload[_D] # We can resume if the payload data is [`true`][]. if not can_reconnect: self._logger.info("received invalid session, will need to start a new session") self._seq = None diff --git a/hikari/impl/special_endpoints.py b/hikari/impl/special_endpoints.py index 3fe723761b..0be096883f 100644 --- a/hikari/impl/special_endpoints.py +++ b/hikari/impl/special_endpoints.py @@ -123,14 +123,14 @@ def __call__( @typing.final class TypingIndicator(special_endpoints.TypingIndicator): - """Result type of `hikari.api.rest.RESTClient.trigger_typing`. + """Result type of [`hikari.api.rest.RESTClient.trigger_typing`][]. This is an object that can either be awaited like a coroutine to trigger the typing indicator once, or an async context manager to keep triggering the typing indicator repeatedly until the context finishes. - .. note:: - This is a helper class that is used by `hikari.api.rest.RESTClient`. + !!! note + This is a helper class that is used by [`hikari.api.rest.RESTClient`][]. You should only ever need to use instances of this class that are produced by that API. """ @@ -205,19 +205,19 @@ async def _keep_typing(self) -> None: @attrs_extensions.with_copy @attrs.define(kw_only=True, weakref_slot=False) class GuildBuilder(special_endpoints.GuildBuilder): - """Result type of `hikari.api.rest.RESTClient.guild_builder`. + """Result type of [`hikari.api.rest.RESTClient.guild_builder`][]. This is used to create a guild in a tidy way using the HTTP API, since the logic behind creating a guild on an API level is somewhat confusing and detailed. - .. note:: - If you call `add_role`, the default roles provided by Discord will + !!! note + If you call [`hikari.api.special_endpoints.GuildBuilder.add_role`][], the default roles provided by Discord will be created. This also applies to the `add_` functions for text channels/voice channels/categories. - .. note:: - Functions that return a `hikari.snowflakes.Snowflake` do + !!! note + Functions that return a [`hikari.snowflakes.Snowflake`][] do **not** provide the final ID that the object will have once the API call is made. The returned IDs are only able to be used to re-reference particular objects while building the guild format @@ -228,24 +228,23 @@ class GuildBuilder(special_endpoints.GuildBuilder): -------- Creating an empty guild: - .. code-block:: python - + ```py guild = await rest.guild_builder("My Server!").create() + ``` Creating a guild with an icon: - .. code-block:: python - + ```py from hikari.files import WebResourceStream guild_builder = rest.guild_builder("My Server!") guild_builder.icon = WebResourceStream("cat.png", "http://...") guild = await guild_builder.create() + ``` Adding roles to your guild: - .. code-block:: python - + ```py from hikari.permissions import Permissions guild_builder = rest.guild_builder("My Server!") @@ -254,20 +253,21 @@ class GuildBuilder(special_endpoints.GuildBuilder): admin_role_id = guild_builder.add_role("Admins", permissions=Permissions.ADMINISTRATOR) await guild_builder.create() + ``` - .. warning:: + !!! warning The first role must always be the `@everyone` role. Adding a text channel to your guild: - .. code-block:: python - + ```py guild_builder = rest.guild_builder("My Server!") category_id = guild_builder.add_category("My safe place") channel_id = guild_builder.add_text_channel("general", parent_id=category_id) await guild_builder.create() + ``` """ # Required arguments. @@ -658,7 +658,7 @@ async def _next_chunk(self) -> typing.Optional[typing.Generator[guilds.GuildBan, return None if self._newest_first: - # These are always returned in ascending order by `.user.id`. + # These are always returned in ascending order by [`.user.id`][]. chunk.reverse() self._first_id = chunk[-1]["user"]["id"] @@ -751,7 +751,7 @@ async def _next_chunk( return None if self._newest_first: - # These are always returned in ascending order by `.user.id`. + # These are always returned in ascending order by [`.user.id`][]. chunk.reverse() self._first_id = chunk[-1]["user"]["id"] @@ -892,7 +892,7 @@ def _maybe_cast( @attrs_extensions.with_copy @attrs.define(kw_only=False, weakref_slot=False) class AutocompleteChoiceBuilder(special_endpoints.AutocompleteChoiceBuilder): - """Standard implementation of `special_endpoints.AutocompleteChoiceBuilder`.""" + """Standard implementation of [`hikari.api.special_endpoints.AutocompleteChoiceBuilder`][].""" _name: str = attrs.field(alias="name") _value: typing.Union[int, str, float] = attrs.field(alias="value") @@ -920,7 +920,7 @@ def build(self) -> typing.MutableMapping[str, typing.Any]: @attrs_extensions.with_copy @attrs.define(weakref_slot=False) class InteractionAutocompleteBuilder(special_endpoints.InteractionAutocompleteBuilder): - """Standard implementation of `hikari.api.special_endpoints.InteractionAutocompleteBuilder`.""" + """Standard implementation of [`hikari.api.special_endpoints.InteractionAutocompleteBuilder`][].""" _choices: typing.Sequence[special_endpoints.AutocompleteChoiceBuilder] = attrs.field(factory=tuple) @@ -945,7 +945,7 @@ def build( @attrs_extensions.with_copy @attrs.define(kw_only=False, weakref_slot=False) class InteractionDeferredBuilder(special_endpoints.InteractionDeferredBuilder): - """Standard implementation of `hikari.api.special_endpoints.InteractionDeferredBuilder`. + """Standard implementation of [`hikari.api.special_endpoints.InteractionDeferredBuilder`][]. Parameters ---------- @@ -988,7 +988,7 @@ def build( @attrs_extensions.with_copy @attrs.define(kw_only=False, weakref_slot=False) class InteractionMessageBuilder(special_endpoints.InteractionMessageBuilder): - """Standard implementation of `hikari.api.special_endpoints.InteractionMessageBuilder`. + """Standard implementation of [`hikari.api.special_endpoints.InteractionMessageBuilder`][]. Parameters ---------- @@ -1207,7 +1207,7 @@ def build( @attrs.define(kw_only=False, weakref_slot=False) class InteractionModalBuilder(special_endpoints.InteractionModalBuilder): - """Standard implementation of `hikari.api.special_endpoints.InteractionModalBuilder`.""" + """Standard implementation of [`hikari.api.special_endpoints.InteractionModalBuilder`][].""" _title: str = attrs.field(alias="title") _custom_id: str = attrs.field(alias="custom_id") @@ -1254,7 +1254,7 @@ def build( @attrs.define(kw_only=False, weakref_slot=False) class CommandBuilder(special_endpoints.CommandBuilder): - """Standard implementation of `hikari.api.special_endpoints.CommandBuilder`.""" + """Standard implementation of [`hikari.api.special_endpoints.CommandBuilder`][].""" _name: str = attrs.field(alias="name") @@ -1850,7 +1850,7 @@ def build(self) -> typing.MutableMapping[str, typing.Any]: @attrs_extensions.with_copy @attrs.define(kw_only=True, weakref_slot=False) class TextInputBuilder(special_endpoints.TextInputBuilder): - """Standard implementation of `hikari.api.special_endpoints.TextInputBuilder`.""" + """Standard implementation of [`hikari.api.special_endpoints.TextInputBuilder`][].""" _custom_id: str = attrs.field(alias="custom_id") _label: str = attrs.field(alias="label") @@ -1950,7 +1950,7 @@ def build(self) -> typing.MutableMapping[str, typing.Any]: @attrs.define(kw_only=True, weakref_slot=False) class MessageActionRowBuilder(special_endpoints.MessageActionRowBuilder): - """Standard implementation of `hikari.api.special_endpoints.ActionRowBuilder`.""" + """Standard implementation of [`hikari.api.special_endpoints.MessageActionRowBuilder`][].""" _components: typing.List[special_endpoints.ComponentBuilder] = attrs.field(alias="components", factory=list) _stored_type: typing.Optional[int] = attrs.field(default=None, init=False) @@ -2077,7 +2077,7 @@ def build(self) -> typing.MutableMapping[str, typing.Any]: @attrs.define(kw_only=True, weakref_slot=False) class ModalActionRowBuilder(special_endpoints.ModalActionRowBuilder): - """Standard implementation of `hikari.api.special_endpoints.ActionRowBuilder`.""" + """Standard implementation of [`hikari.api.special_endpoints.ModalActionRowBuilder`][].""" _components: typing.List[special_endpoints.ComponentBuilder] = attrs.field(alias="components", factory=list) _stored_type: typing.Optional[int] = attrs.field(init=False, default=None) diff --git a/hikari/impl/voice.py b/hikari/impl/voice.py index c5e0312b1c..e4a44e758d 100644 --- a/hikari/impl/voice.py +++ b/hikari/impl/voice.py @@ -190,7 +190,7 @@ async def connect_to( except asyncio.TimeoutError as e: raise errors.VoiceError(f"Could not connect to voice channel {channel} in guild {guild}.") from e - # We will never receive the first endpoint as `None` + # We will never receive the first endpoint as [`None`][] assert server_event.endpoint is not None _LOGGER.debug( diff --git a/hikari/intents.py b/hikari/intents.py index 19591ac942..54e6372730 100644 --- a/hikari/intents.py +++ b/hikari/intents.py @@ -41,37 +41,36 @@ class Intents(enums.Flag): Any events not in an intent category will be fired regardless of what intents you provide. - .. note:: + !!! note Discord now places limits on certain events you can receive without - whitelisting your bot first. On the `Bot` tab in the developer's portal - for your bot, you should now have the option to enable functionality - for receiving these events. + whitelisting your bot first. On the `Bot` tab in the [developer's portal] + (https://discord.com/developers/applications/) for your bot, you should + now have the option to enable functionality for receiving these events. If you attempt to request an intent type that you have not whitelisted your bot for, you will be disconnected on startup with a `4014` closure code. - .. warning:: + !!! warning If you are using the V7 Gateway, you will be REQUIRED to provide some form of intent value when you connect. Failure to do so may result in immediate termination of the session server-side. - This enum is an `enum.IntFlag`, which means that you can use bitwise + This enum is an [`enum.IntFlag`][], which means that you can use bitwise operators to join and splice multiple intents into one value. - For example, if we wish to only refer to the `GUILDS` intent, then it is + For example, if we wish to only refer to the [`hikari.intents.Intents.GUILDS`][] intent, then it is simply a case of accessing it normally. - .. code-block:: python - + ```py my_intents = Intents.GUILDS + ``` If we wanted to have several intents grouped together, we would use the bitwise-or operator to combine them (`|`). This can be done in-place with the `|=` operator if needed. - .. code-block:: python - + ```py # One or two values that fit on one line. my_intents = Intents.GUILD_MESSAGES | Intents.PRIVATE_MESSAGES @@ -85,6 +84,7 @@ class Intents(enums.Flag): Intents.GUILD_MODERATION | Intents.PRIVATE_MESSAGES ) + ``` To check if an intent **is present** in a given intents bitfield, you can use the bitwise-and operator (`&`) to check. This returns the "intersection" @@ -92,8 +92,7 @@ class Intents(enums.Flag): use the `==` operator to check that specific values are present. You can check in-place with the `&=` operator if needed. - .. code-block:: python - + ```py # Check if an intent is set: if (my_intents & Intents.GUILD_MESSAGES) == Intents.GUILD_MESSAGES: print("Guild messages are enabled") @@ -107,12 +106,12 @@ class Intents(enums.Flag): expected_intents = (Intents.GUILD_MESSAGES | Intents.PRIVATE_MESSAGES) if my_intents & expected_intents: print("Messages are enabled in guilds or private messages.") + ``` Removing one or more intents from a combination can be done with the bitwise-xor (`^`) operator. The `^=` operator can do this in-place. - .. code-block:: python - + ```py # Remove GUILD_MESSAGES my_intents = my_intents ^ Intents.GUILD_MESSAGES # or, simplifying: @@ -122,6 +121,7 @@ class Intents(enums.Flag): my_intents = my_intents ^ (Intents.GUILD_MESSAGES | Intents.PRIVATE_MESSAGES) # or, simplifying my_intents ^= (Intents.GUILD_MESSAGES | Intents.PRIVATE_MESSAGES) + ``` What is and is not covered by intents? -------------------------------------- @@ -198,8 +198,8 @@ class Intents(enums.Flag): * `THREAD_MEMBER_UPDATE` * `THREAD_MEMBERS_UPDATE` - .. note:: - Both `GUILDS` and `GUILD_MEMBERS` are required to receive + !!! note + Both [`hikari.intents.Intents.GUILDS`][] and [`hikari.intents.Intents.GUILD_MEMBERS`][] are required to receive `THREAD_MEMBERS_UPDATE`. """ @@ -211,11 +211,11 @@ class Intents(enums.Flag): * `GUILD_MEMBER_REMOVE` * `THREAD_MEMBERS_UPDATE` - .. note:: - Both `GUILDS` and `GUILD_MEMBERS` are required to receive + !!! note + Both [`hikari.intents.Intents.GUILDS`][] and [`hikari.intents.Intents.GUILD_MEMBERS`][] are required to receive `THREAD_MEMBERS_UPDATE`. - .. warning:: + !!! warning This intent is privileged, and requires enabling/whitelisting to use. """ @@ -265,7 +265,7 @@ class Intents(enums.Flag): * `PRESENCE_UPDATE` - .. warning:: + !!! warning This intent is privileged, and requires enabling/whitelisting to use. """ @@ -321,7 +321,7 @@ class Intents(enums.Flag): DM's to the bot and messages that mention it are exempt from this. - .. warning:: + !!! warning This intent is privileged, and requires enabling/whitelisting to use. """ @@ -358,7 +358,7 @@ class Intents(enums.Flag): ALL_GUILDS_PRIVILEGED = GUILD_MEMBERS | GUILD_PRESENCES """All privileged guild intents. - .. warning:: + !!! warning This set of intent is privileged, and requires enabling/whitelisting to use. """ @@ -366,10 +366,10 @@ class Intents(enums.Flag): ALL_GUILDS = ALL_GUILDS_UNPRIVILEGED | ALL_GUILDS_PRIVILEGED """All unprivileged guild intents and all privileged guild intents. - This combines `Intents.ALL_GUILDS_UNPRIVILEGED` and - `Intents.ALL_GUILDS_PRIVILEGED`. + This combines [`hikari.intents.Intents.ALL_GUILDS_UNPRIVILEGED`][] and + [`hikari.intents.Intents.ALL_GUILDS_PRIVILEGED`][]. - .. warning:: + !!! warning This set of intent is privileged, and requires enabling/whitelisting to use. """ @@ -392,7 +392,7 @@ class Intents(enums.Flag): ALL_PRIVILEGED = ALL_GUILDS_PRIVILEGED | MESSAGE_CONTENT """All privileged intents. - .. warning:: + !!! warning This set of intent is privileged, and requires enabling/whitelisting to use. """ @@ -400,7 +400,7 @@ class Intents(enums.Flag): ALL = ALL_UNPRIVILEGED | ALL_PRIVILEGED """All unprivileged and privileged intents. - .. warning:: + !!! warning This set of intent is privileged, and requires enabling/whitelisting to use. """ @@ -409,7 +409,7 @@ class Intents(enums.Flag): def is_privileged(self) -> bool: """Determine whether the intent requires elevated privileges. - If this is `True`, you will be required to opt-in to using + If this is [`True`][], you will be required to opt-in to using this intent on the Discord Developer Portal before you can utilise it in your application. """ diff --git a/hikari/interactions/base_interactions.py b/hikari/interactions/base_interactions.py index ae5227a0b4..a4cc54e1fa 100644 --- a/hikari/interactions/base_interactions.py +++ b/hikari/interactions/base_interactions.py @@ -93,8 +93,8 @@ class ResponseType(int, enums.Enum): MESSAGE_CREATE = 4 """An immediate message response to an interaction. - * `InteractionType.APPLICATION_COMMAND` - * `InteractionType.MESSAGE_COMPONENT` + * [`hikari.interactions.base_interactions.InteractionType.APPLICATION_COMMAND`][] + * [`hikari.interactions.base_interactions.InteractionType.MESSAGE_COMPONENT`][] """ DEFERRED_MESSAGE_CREATE = 5 @@ -105,8 +105,8 @@ class ResponseType(int, enums.Enum): This is valid for the following interaction types: - * `InteractionType.APPLICATION_COMMAND` - * `InteractionType.MESSAGE_COMPONENT` + * [`hikari.interactions.base_interactions.InteractionType.APPLICATION_COMMAND`][] + * [`hikari.interactions.base_interactions.InteractionType.MESSAGE_COMPONENT`][] """ DEFERRED_MESSAGE_UPDATE = 6 @@ -114,7 +114,7 @@ class ResponseType(int, enums.Enum): This is valid for the following interaction types: - * `InteractionType.MESSAGE_COMPONENT` + * [`hikari.interactions.base_interactions.InteractionType.MESSAGE_COMPONENT`][] """ MESSAGE_UPDATE = 7 @@ -122,7 +122,7 @@ class ResponseType(int, enums.Enum): This is valid for the following interaction types: - * `InteractionType.MESSAGE_COMPONENT` + * [`hikari.interactions.base_interactions.InteractionType.MESSAGE_COMPONENT`][] """ AUTOCOMPLETE = 8 @@ -130,7 +130,7 @@ class ResponseType(int, enums.Enum): This is valid for the following interaction types: - * `InteractionType.AUTOCOMPLETE` + * [`hikari.interactions.base_interactions.InteractionType.AUTOCOMPLETE`][] """ MODAL = 9 @@ -138,7 +138,7 @@ class ResponseType(int, enums.Enum): This is valid for the following interaction types: - * `InteractionType.MODAL_SUBMIT` + * [`hikari.interactions.base_interactions.InteractionType.MODAL_SUBMIT`][] """ @@ -149,8 +149,8 @@ class ResponseType(int, enums.Enum): This includes the following: -* `ResponseType.MESSAGE_CREATE` -* `ResponseType.MESSAGE_UPDATE` +* [`hikari.interactions.base_interactions.ResponseType.MESSAGE_CREATE`][] +* [`hikari.interactions.base_interactions.ResponseType.MESSAGE_UPDATE`][] """ MessageResponseTypesT = typing.Literal[ResponseType.MESSAGE_CREATE, 4, ResponseType.MESSAGE_UPDATE, 7] @@ -158,8 +158,8 @@ class ResponseType(int, enums.Enum): The following are valid for this: -* `ResponseType.MESSAGE_CREATE`/`4` -* `ResponseType.MESSAGE_UPDATE`/`7` +* [`hikari.interactions.base_interactions.ResponseType.MESSAGE_CREATE`][]/`4` +* [`hikari.interactions.base_interactions.ResponseType.MESSAGE_UPDATE`][]/`7` """ DEFERRED_RESPONSE_TYPES: typing.Final[typing.AbstractSet[DeferredResponseTypesT]] = frozenset( @@ -169,8 +169,8 @@ class ResponseType(int, enums.Enum): This includes the following: -* `ResponseType.DEFERRED_MESSAGE_CREATE` -* `ResponseType.DEFERRED_MESSAGE_UPDATE` +* [`hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_CREATE`][] +* [`hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_UPDATE`][] """ DeferredResponseTypesT = typing.Literal[ @@ -180,8 +180,8 @@ class ResponseType(int, enums.Enum): The following are valid for this: -* `ResponseType.DEFERRED_MESSAGE_CREATE`/`5` -* `ResponseType.DEFERRED_MESSAGE_UPDATE`/`6` +* [`hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_CREATE`][]/`5` +* [`hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_UPDATE`][]/`6` """ @@ -268,9 +268,9 @@ async def create_initial_response( ) -> None: """Create the initial response for this interaction. - .. warning:: + !!! warning Calling this on an interaction which already has an initial - response will result in this raising a `hikari.errors.NotFoundError`. + response will result in this raising a [`hikari.errors.NotFoundError`][]. This includes if the REST interaction server has already responded to the request. @@ -283,11 +283,11 @@ async def create_initial_response( ---------------- content : hikari.undefined.UndefinedOr[typing.Any] If provided, the message contents. If - `hikari.undefined.UNDEFINED`, then nothing will be sent + [`hikari.undefined.UNDEFINED`][], then nothing will be sent in the content. Any other value here will be cast to a - `str`. + [`str`][]. - If this is a `hikari.embeds.Embed` and no `embed` nor `embeds` kwarg + 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. attachment : hikari.undefined.UndefinedNoneOr[typing.Union[hikari.files.Resourceish, hikari.messages.Attachment]] @@ -309,8 +309,8 @@ async def create_initial_response( If provided, the message flags this response should have. As of writing the only message flags which can be set here are - `hikari.messages.MessageFlag.EPHEMERAL`, `hikari.messages.MessageFlag.SUPPRESS_NOTIFICATIONS` - and `hikari.messages.MessageFlag.SUPPRESS_EMBEDS`. + [`hikari.messages.MessageFlag.EPHEMERAL`][], [`hikari.messages.MessageFlag.SUPPRESS_NOTIFICATIONS`][] + and [`hikari.messages.MessageFlag.SUPPRESS_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. @@ -318,20 +318,20 @@ async def create_initial_response( If provided, whether the message should parse @everyone/@here mentions. 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 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 + [`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 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 + [`hikari.snowflakes.Snowflake`][], or + [`hikari.guilds.PartialRole`][] derivatives to enforce mentioning specific roles. Raises @@ -401,16 +401,16 @@ async def edit_initial_response( ) -> messages.Message: """Edit the initial response of this command interaction. - .. note:: + !!! note Mentioning everyone, roles, or users in message edits currently will not send a push notification showing a new mention to people on Discord. It will still highlight in their chat as if they were mentioned, however. - .. warning:: + !!! warning If you specify a text `content`, `mentions_everyone`, `mentions_reply`, `user_mentions`, and `role_mentions` will default - to `False` as the message will be re-parsed for mentions. This will + to [`False`][] as the message will be re-parsed for mentions. This will also occur if only one of the four are specified This is a limitation of Discord's design. If in doubt, specify all @@ -420,71 +420,71 @@ async def edit_initial_response( ---------------- content : hikari.undefined.UndefinedNoneOr[typing.Any] If provided, the message contents. If - `hikari.undefined.UNDEFINED`, then nothing will be sent + [`hikari.undefined.UNDEFINED`][], then nothing will be sent in the content. Any other value here will be cast to a - `str`. + [`str`][]. - If this is a `hikari.embeds.Embed` and neither the + If this is a [`hikari.embeds.Embed`][] and neither the `embed` or `embeds` kwargs are provided or if this is a - `hikari.files.Resourceish` and neither the `attachment` or + [`hikari.files.Resourceish`][] and neither the `attachment` or `attachments` kwargs are provided, the values will be overwritten. This allows for simpler syntax when sending an embed or an attachment alone. - Likewise, if this is a `hikari.files.Resource`, then the + 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. attachment : hikari.undefined.UndefinedNoneOr[typing.Union[hikari.files.Resourceish, hikari.messages.Attachment]] If provided, the attachment to set on the message. If - `hikari.undefined.UNDEFINED`, the previous attachment, if - present, is not changed. If this is `None`, then the + [`hikari.undefined.UNDEFINED`][], the previous attachment, if + present, is not changed. If this is [`None`][], then the attachment is removed, if present. Otherwise, the new attachment that was provided will be attached. attachments : hikari.undefined.UndefinedNoneOr[typing.Sequence[typing.Union[hikari.files.Resourceish, hikari.messages.Attachment]]] If provided, the attachments to set on the message. If - `hikari.undefined.UNDEFINED`, the previous attachments, if - present, are not changed. If this is `None`, then the + [`hikari.undefined.UNDEFINED`][], the previous attachments, if + present, are not changed. If this is [`None`][], then the attachments is removed, if present. Otherwise, the new attachments that were provided will be attached. component : hikari.undefined.UndefinedNoneOr[hikari.api.special_endpoints.ComponentBuilder] If provided, builder object of the component to set for this message. This component will replace any previously set components and passing - `None` will remove all components. + [`None`][] will remove all components. components : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.api.special_endpoints.ComponentBuilder]] If provided, a sequence of the component builder objects set for this message. These components will replace any previously set - components and passing `None` or an empty sequence will + components and passing [`None`][] or an empty sequence will remove all components. embed : hikari.undefined.UndefinedNoneOr[hikari.embeds.Embed] If provided, the embed to set on the message. If - `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed. - If this is `None` then any present embeds are removed. + [`hikari.undefined.UNDEFINED`][], the previous embed(s) are not changed. + If this is [`None`][] then any present embeds are removed. Otherwise, the new embed that was provided will be used as the replacement. embeds : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.embeds.Embed]] If provided, the embeds to set on the message. If - `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed. - If this is `None` then any present embeds are removed. + [`hikari.undefined.UNDEFINED`][], the previous embed(s) are not changed. + If this is [`None`][] then any present embeds are removed. Otherwise, the new embeds that were provided will be used as the replacement. mentions_everyone : hikari.undefined.UndefinedOr[bool] If provided, whether the message should parse @everyone/@here mentions. 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 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 + [`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 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 + [`hikari.snowflakes.Snowflake`][], or + [`hikari.guilds.PartialRole`][] derivatives to enforce mentioning specific roles. Returns @@ -607,8 +607,8 @@ def build_modal_response(self, title: str, custom_id: str) -> special_endpoints. class InteractionMember(guilds.Member): """Model of the member who triggered an interaction. - Unlike `hikari.guilds.Member`, this object comes with an extra - `InteractionMember.permissions` field. + Unlike [`hikari.guilds.Member`][], this object comes with an extra + [`hikari.interactions.base_interactions.InteractionMember.permissions`][] field. """ permissions: permissions_.Permissions = attrs.field(eq=False, hash=False, repr=False) diff --git a/hikari/interactions/command_interactions.py b/hikari/interactions/command_interactions.py index 09741cf7a5..f57facbe18 100644 --- a/hikari/interactions/command_interactions.py +++ b/hikari/interactions/command_interactions.py @@ -61,8 +61,8 @@ This includes: -* `hikari.interactions.base_interactions.ResponseType.MESSAGE_CREATE` -* `hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_CREATE` +* [`hikari.interactions.base_interactions.ResponseType.MESSAGE_CREATE`][] +* [`hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_CREATE`][] """ CommandResponseTypesT = typing.Literal[ @@ -72,15 +72,15 @@ The following types are valid for this: -* `hikari.interactions.base_interactions.ResponseType.MESSAGE_CREATE`/`4` -* `hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_CREATE`/`5` +* [`hikari.interactions.base_interactions.ResponseType.MESSAGE_CREATE`][]/`4` +* [`hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_CREATE`][]/`5` """ InteractionChannel = base_interactions.InteractionChannel -"""Deprecated alias of `hikari.base_interactions.InteractionChannel`.""" +"""Deprecated alias of [`hikari.interactions.base_interactions.InteractionChannel`][].""" ResolvedOptionData = base_interactions.ResolvedOptionData -"""Deprecated alias of `hikari.base_interactions.ResolvedOptionData`.""" +"""Deprecated alias of [`hikari.interactions.base_interactions.ResolvedOptionData`][].""" @attrs_extensions.with_copy @@ -97,7 +97,8 @@ class CommandInteractionOption: value: typing.Union[snowflakes.Snowflake, str, int, float, bool, None] = attrs.field(repr=True) """Value provided for this option. - Either `CommandInteractionOption.value` or `CommandInteractionOption.options` + Either [`hikari.interactions.command_interactions.CommandInteractionOption.value`][] + or [`hikari.interactions.command_interactions.CommandInteractionOption.options`][] will be provided with `value` being provided when an option is provided as a parameter with a value and `options` being provided when an option donates a subcommand or group. @@ -106,7 +107,8 @@ class CommandInteractionOption: options: typing.Optional[typing.Sequence[Self]] = attrs.field(repr=True) """Options provided for this option. - Either `CommandInteractionOption.value` or `CommandInteractionOption.options` + Either [`hikari.interactions.command_interactions.CommandInteractionOption.value`][] + or [`hikari.interactions.command_interactions.CommandInteractionOption.options`][] will be provided with `value` being provided when an option is provided as a parameter with a value and `options` being provided when an option donates a subcommand or group. @@ -140,25 +142,25 @@ class BaseCommandInteraction(base_interactions.PartialInteraction): guild_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=True) """ID of the guild this command interaction event was triggered in. - This will be `None` for command interactions triggered in DMs. + This will be [`None`][] for command interactions triggered in DMs. """ guild_locale: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=True) """The preferred language of the guild this command interaction was triggered in. - This will be `None` for command interactions triggered in DMs. + This will be [`None`][] for command interactions triggered in DMs. - .. note:: - This value can usually only be changed if `COMMUNITY` is in `hikari.guilds.Guild.features` + !!! note + This value can usually only be changed if [COMMUNITY] is in [`hikari.guilds.Guild.features`][] for the guild and will otherwise default to `en-US`. """ member: typing.Optional[base_interactions.InteractionMember] = attrs.field(eq=False, hash=False, repr=True) """The member who triggered this command interaction. - This will be `None` for command interactions triggered in DMs. + This will be [`None`][] for command interactions triggered in DMs. - .. note:: + !!! note This member object comes with the extra field `permissions` which contains the member's permissions in the current channel. """ @@ -192,7 +194,7 @@ async def fetch_channel(self) -> channels.TextableChannel: hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -211,15 +213,15 @@ async def fetch_channel(self) -> channels.TextableChannel: def get_channel(self) -> typing.Optional[channels.TextableGuildChannel]: """Get the guild channel this was triggered in from the cache. - .. note:: - This will always return `None` for interactions triggered + !!! note + This will always return [`None`][] for interactions triggered in a DM channel. Returns ------- typing.Optional[hikari.channels.TextableGuildChannel] The object of the guild channel that was found in the cache or - `None`. + [`None`][]. """ if isinstance(self.app, traits.CacheAware): channel = self.app.cache.get_guild_channel(self.channel_id) @@ -260,7 +262,7 @@ async def fetch_guild(self) -> typing.Optional[guilds.RESTGuild]: Returns ------- typing.Optional[hikari.guilds.RESTGuild] - Object of the guild this interaction happened in or `None` + Object of the guild this interaction happened in or [`None`][] if this occurred within a DM channel. Raises @@ -288,7 +290,7 @@ def get_guild(self) -> typing.Optional[guilds.GatewayGuild]: Returns ------- typing.Optional[hikari.guilds.GatewayGuild] - The object of the guild if found, else `None`. + The object of the guild if found, else [`None`][]. """ if self.guild_id and isinstance(self.app, traits.CacheAware): return self.app.cache.get_guild(self.guild_id) @@ -320,15 +322,14 @@ class CommandInteraction( def build_response(self) -> special_endpoints.InteractionMessageBuilder: """Get a message response builder for use in the REST server flow. - .. note:: + !!! note For interactions received over the gateway - `CommandInteraction.create_initial_response` should be used to set + [`hikari.interactions.command_interactions.CommandInteraction.create_initial_response`][] should be used to set the interaction response message. Examples -------- - .. code-block:: python - + ```py async def handle_command_interaction(interaction: CommandInteraction) -> InteractionMessageBuilder: return ( interaction @@ -336,6 +337,7 @@ async def handle_command_interaction(interaction: CommandInteraction) -> Interac .add_embed(Embed(description="Hi there")) .set_content("Konnichiwa") ) + ``` Returns ------- @@ -347,24 +349,24 @@ async def handle_command_interaction(interaction: CommandInteraction) -> Interac def build_deferred_response(self) -> special_endpoints.InteractionDeferredBuilder: """Get a deferred message response builder for use in the REST server flow. - .. note:: + !!! note For interactions received over the gateway - `CommandInteraction.create_initial_response` should be used to set + [`hikari.interactions.command_interactions.CommandInteraction.create_initial_response`][] should be used to set the interaction response message. - .. note:: - Unlike `hikari.api.special_endpoints.InteractionMessageBuilder`, + !!! note + Unlike [`hikari.api.special_endpoints.InteractionMessageBuilder`][], the result of this call can be returned as is without any modifications being made to it. Examples -------- - .. code-block:: python - + ```py async def handle_command_interaction(interaction: CommandInteraction) -> InteractionMessageBuilder: yield interaction.build_deferred_response() await interaction.edit_initial_response("Pong!") + ``` Returns ------- @@ -387,9 +389,9 @@ def build_response( ) -> special_endpoints.InteractionAutocompleteBuilder: """Get a message response builder for use in the REST server flow. - .. note:: + !!! note For interactions received over the gateway - `AutocompleteInteraction.create_response` should be used to set + [`hikari.interactions.command_interactions.AutocompleteInteraction.create_response`][] should be used to set the interaction response. Parameters @@ -399,8 +401,7 @@ def build_response( Examples -------- - .. code-block:: python - + ```py async def handle_autocomplete_interaction(interaction: AutocompleteInteraction) -> InteractionAutocompleteBuilder: return ( interaction @@ -412,6 +413,7 @@ async def handle_autocomplete_interaction(interaction: AutocompleteInteraction) ] ) ) + ``` Returns ------- diff --git a/hikari/interactions/component_interactions.py b/hikari/interactions/component_interactions.py index 2b43bda1fd..8ed1e98d79 100644 --- a/hikari/interactions/component_interactions.py +++ b/hikari/interactions/component_interactions.py @@ -65,10 +65,10 @@ This includes: -* `hikari.interactions.base_interactions.ResponseType.MESSAGE_CREATE` -* `hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_CREATE` -* `hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_UPDATE` -* `hikari.interactions.base_interactions.ResponseType.MESSAGE_UPDATE` +* [`hikari.interactions.base_interactions.ResponseType.MESSAGE_CREATE`][] +* [`hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_CREATE`][] +* [`hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_UPDATE`][] +* [`hikari.interactions.base_interactions.ResponseType.MESSAGE_UPDATE`][] """ ComponentResponseTypesT = typing.Union[_ImmediateTypesT, _DeferredTypesT] @@ -76,10 +76,10 @@ The following types are valid for this: -* `hikari.interactions.base_interactions.ResponseType.MESSAGE_CREATE`/`4` -* `hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_CREATE`/`5` -* `hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_UPDATE`/`6` -* `hikari.interactions.base_interactions.ResponseType.MESSAGE_UPDATE`/`7` +* [`hikari.interactions.base_interactions.ResponseType.MESSAGE_CREATE`][]/`4` +* [`hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_CREATE`][]/`5` +* [`hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_UPDATE`][]/`6` +* [`hikari.interactions.base_interactions.ResponseType.MESSAGE_UPDATE`][]/`7` """ @@ -95,8 +95,8 @@ class ComponentInteraction( component_type: typing.Union[components_.ComponentType, int] = attrs.field(eq=False) """The type of component which triggers this interaction. - .. note:: - This will never be `ButtonStyle.LINK` as link buttons don't trigger + !!! note + This will never be [`hikari.components.ButtonStyle.LINK`][] as link buttons don't trigger interactions. """ @@ -112,16 +112,16 @@ class ComponentInteraction( guild_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False) """ID of the guild this interaction was triggered in. - This will be `None` for component interactions triggered in DMs. + This will be [`None`][] for component interactions triggered in DMs. """ guild_locale: typing.Optional[typing.Union[str, locales.Locale]] = attrs.field(eq=False, hash=False, repr=True) """The preferred language of the guild this component interaction was triggered in. - This will be `None` for component interactions triggered in DMs. + This will be [`None`][] for component interactions triggered in DMs. - .. note:: - This value can usually only be changed if `COMMUNITY` is in `hikari.guilds.Guild.features` + !!! note + This value can usually only be changed if [COMMUNITY] is in [`hikari.guilds.Guild.features`][] for the guild and will otherwise default to `en-US`. """ @@ -131,9 +131,9 @@ class ComponentInteraction( member: typing.Optional[base_interactions.InteractionMember] = attrs.field(eq=False, hash=False, repr=True) """The member who triggered this interaction. - This will be `None` for interactions triggered in DMs. + This will be [`None`][] for interactions triggered in DMs. - .. note:: + !!! note This member object comes with the extra field `permissions` which contains the member's permissions in the current channel. """ @@ -150,9 +150,9 @@ class ComponentInteraction( def build_response(self, type_: _ImmediateTypesT, /) -> special_endpoints.InteractionMessageBuilder: """Get a message response builder for use in the REST server flow. - .. note:: + !!! note For interactions received over the gateway - `ComponentInteraction.create_initial_response` should be used to set + [`hikari.interactions.component_interactions.ComponentInteraction.create_initial_response`][] should be used to set the interaction response message. Parameters @@ -162,13 +162,12 @@ def build_response(self, type_: _ImmediateTypesT, /) -> special_endpoints.Intera This may be one of the following: - * `hikari.interactions.base_interactions.ResponseType.MESSAGE_CREATE` - * `hikari.interactions.base_interactions.ResponseType.MESSAGE_UPDATE` + * [`hikari.interactions.base_interactions.ResponseType.MESSAGE_CREATE`][] + * [`hikari.interactions.base_interactions.ResponseType.MESSAGE_UPDATE`][] Examples -------- - .. code-block:: python - + ```py async def handle_component_interaction(interaction: ComponentInteraction) -> InteractionMessageBuilder: return ( interaction @@ -176,6 +175,7 @@ async def handle_component_interaction(interaction: ComponentInteraction) -> Int .add_embed(Embed(description="Hi there")) .set_content("Konnichiwa") ) + ``` Returns ------- @@ -190,13 +190,13 @@ async def handle_component_interaction(interaction: ComponentInteraction) -> Int def build_deferred_response(self, type_: _DeferredTypesT, /) -> special_endpoints.InteractionDeferredBuilder: """Get a deferred message response builder for use in the REST server flow. - .. note:: + !!! note For interactions received over the gateway - `ComponentInteraction.create_initial_response` should be used to set + [`hikari.interactions.component_interactions.ComponentInteraction.create_initial_response`][] should be used to set the interaction response message. - .. note:: - Unlike `hikari.api.special_endpoints.InteractionMessageBuilder`, + !!! note + Unlike [`hikari.api.special_endpoints.InteractionMessageBuilder`][], the result of this call can be returned as is without any modifications being made to it. @@ -207,8 +207,8 @@ def build_deferred_response(self, type_: _DeferredTypesT, /) -> special_endpoint This may be one of the following: - * `hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_CREATE` - * `hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_UPDATE` + * [`hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_CREATE`][] + * [`hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_UPDATE`][] Returns ------- @@ -226,14 +226,14 @@ async def fetch_channel(self) -> channels.TextableChannel: Returns ------- hikari.channels.TextableChannel - The channel. This will be a _derivative_ of `hikari.channels.TextableChannel`. + The channel. This will be a _derivative_ of [`hikari.channels.TextableChannel`][]. Raises ------ hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -252,15 +252,15 @@ async def fetch_channel(self) -> channels.TextableChannel: def get_channel(self) -> typing.Union[channels.GuildTextChannel, channels.GuildNewsChannel, None]: """Get the guild channel this interaction occurred in. - .. note:: - This will always return `None` for interactions triggered + !!! note + This will always return [`None`][] for interactions triggered in a DM channel. Returns ------- typing.Union[hikari.channels.GuildTextChannel, hikari.channels.GuildNewsChannel, None] The object of the guild channel that was found in the cache or - `None`. + [`None`][]. """ if isinstance(self.app, traits.CacheAware): channel = self.app.cache.get_guild_channel(self.channel_id) @@ -275,7 +275,7 @@ async def fetch_guild(self) -> typing.Optional[guilds.RESTGuild]: Returns ------- typing.Optional[hikari.guilds.RESTGuild] - Object of the guild this interaction happened in or `None` + Object of the guild this interaction happened in or [`None`][] if this occurred within a DM channel. Raises @@ -303,7 +303,7 @@ def get_guild(self) -> typing.Optional[guilds.GatewayGuild]: Returns ------- typing.Optional[hikari.guilds.GatewayGuild] - The object of the guild if found, else `None`. + The object of the guild if found, else [`None`][]. """ if self.guild_id and isinstance(self.app, traits.CacheAware): return self.app.cache.get_guild(self.guild_id) diff --git a/hikari/interactions/modal_interactions.py b/hikari/interactions/modal_interactions.py index be819bdc95..d27ef356ad 100644 --- a/hikari/interactions/modal_interactions.py +++ b/hikari/interactions/modal_interactions.py @@ -41,6 +41,7 @@ if typing.TYPE_CHECKING: from hikari import components as components_ + from hikari import locales from hikari import users as _users from hikari.api import special_endpoints @@ -58,10 +59,10 @@ The following types are valid for this: -* `hikari.interactions.base_interactions.ResponseType.MESSAGE_CREATE`/`4` -* `hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_CREATE`/`5` -* `hikari.interactions.base_interactions.ResponseType.MESSAGE_UPDATE`/`7` -* `hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_UPDATE`/`6` +* [`hikari.interactions.base_interactions.ResponseType.MESSAGE_CREATE`][]/`4` +* [`hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_CREATE`][]/`5` +* [`hikari.interactions.base_interactions.ResponseType.MESSAGE_UPDATE`][]/`7` +* [`hikari.interactions.base_interactions.ResponseType.DEFERRED_MESSAGE_UPDATE`][]/`6` """ @@ -79,31 +80,32 @@ class ModalInteraction(base_interactions.MessageResponseMixin[ModalResponseTypes guild_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=True) """ID of the guild this modal interaction event was triggered in. - This will be `None` for modal interactions triggered in DMs. + This will be [`None`][] for modal interactions triggered in DMs. """ - guild_locale: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=True) + guild_locale: typing.Union[str, locales.Locale, None] = attrs.field(eq=False, hash=False, repr=True) """The preferred language of the guild this modal interaction was triggered in. - This will be `None` for modal interactions triggered in DMs. + This will be [`None`][] for modal interactions triggered in DMs. - .. note:: - This value can usually only be changed if `COMMUNITY` is in `hikari.guilds.Guild.features` - for the guild and will otherwise default to `en-US`. + !!! note + This value can usually only be changed if [`hikari.guilds.GuildFeature.COMMUNITY`][] + is in [`hikari.guilds.Guild.features`][] for the guild and will otherwise + default to [`hikari.locales.Locale.EN_US`][]. """ message: typing.Optional[messages.Message] = attrs.field(eq=False, repr=False) """The message whose component triggered the modal. - This will be None if the modal was a response to a command. + This will be [`None`][] if the modal was a response to a command. """ member: typing.Optional[base_interactions.InteractionMember] = attrs.field(eq=False, hash=False, repr=True) """The member who triggered this modal interaction. - This will be `None` for modal interactions triggered in DMs. + This will be [`None`][] for modal interactions triggered in DMs. - .. note:: + !!! note This member object comes with the extra field `permissions` which contains the member's permissions in the current channel. """ @@ -134,7 +136,8 @@ async def fetch_channel(self) -> channels.TextableChannel: hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.ForbiddenError - If you are missing the `READ_MESSAGES` permission in the channel. + If you are missing the [`hikari.permissions.Permissions.VIEW_CHANNEL`][] + permission in the channel. hikari.errors.NotFoundError If the channel is not found. hikari.errors.RateLimitTooLongError @@ -153,15 +156,15 @@ async def fetch_channel(self) -> channels.TextableChannel: def get_channel(self) -> typing.Optional[channels.TextableGuildChannel]: """Get the guild channel this interaction was triggered in from the cache. - .. note:: - This will always return `None` for interactions triggered + !!! note + This will always return [`None`][] for interactions triggered in a DM channel. Returns ------- typing.Optional[hikari.channels.TextableGuildChannel] The object of the guild channel that was found in the cache or - `None`. + [`None`][]. """ if isinstance(self.app, traits.CacheAware): channel = self.app.cache.get_guild_channel(self.channel_id) @@ -176,7 +179,7 @@ async def fetch_guild(self) -> typing.Optional[guilds.RESTGuild]: Returns ------- typing.Optional[hikari.guilds.RESTGuild] - Object of the guild this interaction happened in or `None` + Object of the guild this interaction happened in or [`None`][] if this occurred within a DM channel. Raises @@ -204,7 +207,7 @@ def get_guild(self) -> typing.Optional[guilds.GatewayGuild]: Returns ------- typing.Optional[hikari.guilds.GatewayGuild] - The object of the guild if found, else `None`. + The object of the guild if found, else [`None`][]. """ if self.guild_id and isinstance(self.app, traits.CacheAware): return self.app.cache.get_guild(self.guild_id) @@ -214,15 +217,14 @@ def get_guild(self) -> typing.Optional[guilds.GatewayGuild]: def build_response(self) -> special_endpoints.InteractionMessageBuilder: """Get a message response builder for use in the REST server flow. - .. note:: + !!! note For interactions received over the gateway - `ModalInteraction.create_initial_response` should be used to set - the interaction response message. + [`hikari.interactions.modal_interactions.ModalInteraction.create_initial_response`][] + should be used to set the interaction response message. Examples -------- - .. code-block:: python - + ```py async def handle_modal_interaction(interaction: ModalInteraction) -> InteractionMessageBuilder: return ( interaction @@ -230,6 +232,7 @@ async def handle_modal_interaction(interaction: ModalInteraction) -> Interaction .add_embed(Embed(description="Hi there")) .set_content("Konnichiwa") ) + ``` Returns ------- @@ -241,13 +244,13 @@ async def handle_modal_interaction(interaction: ModalInteraction) -> Interaction def build_deferred_response(self) -> special_endpoints.InteractionDeferredBuilder: """Get a deferred message response builder for use in the REST server flow. - .. note:: + !!! note For interactions received over the gateway - `ModalInteraction.create_initial_response` should be used to set - the interaction response message. + [`hikari.interactions.modal_interactions.ModalInteraction.create_initial_response`][] + should be used to set the interaction response message. - .. note:: - Unlike `hikari.api.special_endpoints.InteractionMessageBuilder`, + !!! note + Unlike [`hikari.api.special_endpoints.InteractionMessageBuilder`][], the result of this call can be returned as is without any modifications being made to it. diff --git a/hikari/internal/aio.py b/hikari/internal/aio.py index e2bb8dc7d6..5c6156b6e3 100644 --- a/hikari/internal/aio.py +++ b/hikari/internal/aio.py @@ -57,9 +57,9 @@ def completed_future(result: typing.Optional[T_inv] = None, /) -> asyncio.Future ---------- result : T The value to set for the result of the future. - `T` is a generic type placeholder for the type that - the future will have set as the result. `T` may be `None`, in - which case, this will return `asyncio.Future[None]`. + [`T`][] is a generic type placeholder for the type that + the future will have set as the result. `T` may be [`None`][], in + which case, this will return [`asyncio.Future`][][[`None`][]]. Returns ------- @@ -116,7 +116,7 @@ async def first_completed(*aws: typing.Awaitable[typing.Any], timeout: typing.Op If the first awaitable raises an exception, then that exception will be propagated. - .. note:: + !!! note If more than one awaitable is completed before entering this call, then the first future is always returned. @@ -125,7 +125,7 @@ async def first_completed(*aws: typing.Awaitable[typing.Any], timeout: typing.Op *aws : typing.Awaitable[typing.Any] Awaitables to wait for. timeout : typing.Optional[float] - Optional timeout to wait for, or `None` to not use one. + Optional timeout to wait for, or [`None`][] to not use one. If the timeout is reached, all awaitables are cancelled immediately. """ fs = tuple(map(asyncio.ensure_future, aws)) @@ -158,7 +158,7 @@ async def all_of(*aws: typing.Awaitable[T_co], timeout: typing.Optional[float] = *aws : typing.Awaitable[T_co] Awaitables to wait for. timeout : typing.Optional[float] - Optional timeout to wait for, or `None` to not use one. + Optional timeout to wait for, or [`None`][] to not use one. If the timeout is reached, all awaitables are cancelled immediately. Returns diff --git a/hikari/internal/attrs_extensions.py b/hikari/internal/attrs_extensions.py index 4af6a2a152..31ca4043f9 100644 --- a/hikari/internal/attrs_extensions.py +++ b/hikari/internal/attrs_extensions.py @@ -20,7 +20,7 @@ # 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. -"""Utility for extending and optimising the usage of `attr` models.""" +"""Utility for extending and optimising the usage of [`attr`][] models.""" from __future__ import annotations __all__: typing.Sequence[str] = ( @@ -91,7 +91,7 @@ def get_fields_definition( # TODO: can we get if the init wasn't generated for the class? def generate_shallow_copier(cls: typing.Type[ModelT]) -> typing.Callable[[ModelT], ModelT]: - """Generate a function for shallow copying an attrs model with `init` enabled. + """Generate a function for shallow copying an attrs model with [`init`][] enabled. Parameters ---------- @@ -138,7 +138,7 @@ def get_or_generate_shallow_copier(cls: typing.Type[ModelT]) -> typing.Callable[ def copy_attrs(model: ModelT) -> ModelT: - """Shallow copy an attrs model with `init` enabled. + """Shallow copy an attrs model with [`init`][] enabled. Parameters ---------- @@ -166,7 +166,7 @@ def _normalize_kwargs_and_setters( def generate_deep_copier( cls: typing.Type[ModelT], ) -> typing.Callable[[ModelT, typing.MutableMapping[int, typing.Any]], None]: - """Generate a function for deep copying an attrs model with `init` enabled. + """Generate a function for deep copying an attrs model with [`init`][] enabled. Parameters ---------- @@ -221,11 +221,11 @@ def get_or_generate_deep_copier( def deep_copy_attrs(model: ModelT, memo: typing.Optional[typing.MutableMapping[int, typing.Any]] = None) -> ModelT: - """Deep copy an attrs model with `init` enabled. + """Deep copy an attrs model with [`init`][] enabled. - .. note:: + !!! note This won't deep copy attributes where "skip_deep_copy" is set to - `True` in their metadata. + [`True`][] in their metadata. Parameters ---------- @@ -252,7 +252,7 @@ def deep_copy_attrs(model: ModelT, memo: typing.Optional[typing.MutableMapping[i def with_copy(cls: typing.Type[ModelT]) -> typing.Type[ModelT]: """Add a custom implementation for copying attrs models to a class. - .. note:: + !!! note This will only work if the class has an attrs generated init. """ cls.__copy__ = copy_attrs # type: ignore[attr-defined] diff --git a/hikari/internal/cache.py b/hikari/internal/cache.py index e56b192b67..dfc5b5405f 100644 --- a/hikari/internal/cache.py +++ b/hikari/internal/cache.py @@ -95,7 +95,7 @@ class CacheMappingView(cache.CacheView[KeyT, ValueT]): wrapper or in a data form. builder : typing.Optional[typing.Callable[[DataT], ValueT]] The callable used to build entities before they're returned by the - mapping. This is used to cover the case when items stores `DataT` objects. + mapping. This is used to cover the case when items stores [`DataT`][] objects. """ __slots__: typing.Sequence[str] = ("_data", "_builder") @@ -180,49 +180,44 @@ class GuildRecord: is_available: typing.Optional[bool] = attrs.field(default=None) """Whether the cached guild is available or not. - This will be `None` when no `GuildRecord.guild` is also - `None` else `bool`. + This will be [`None`][] when no `guild` is also + [`None`][] else [`bool`][]. """ guild: typing.Optional[guilds.GatewayGuild] = attrs.field(default=None) """A cached guild object. - This will be `hikari.guilds.GatewayGuild` or `None` if not cached. + This will be [`None`][] if not cached. """ channels: typing.Optional[typing.MutableSet[snowflakes.Snowflake]] = attrs.field(default=None) """A set of the IDs of the guild channels cached for this guild. - This will be `None` if no channels are cached for this guild else - `typing.MutableSet[hikari.snowflakes.Snowflake]` of channel IDs. + This will be [`None`][] if no channels are cached for this guild. """ threads: typing.Optional[typing.MutableSet[snowflakes.Snowflake]] = attrs.field(default=None) """A set of the IDs of the guild threads cached for this guild. - This will be `None` if no threads are cached for this guild else - `typing.MutableSet[hikari.snowflakes.Snowflake]` of thread IDs. + This will be [`None`][] if no threads are cached for this guild. """ emojis: typing.Optional[typing.MutableSet[snowflakes.Snowflake]] = attrs.field(default=None) """A set of the IDs of the emojis cached for this guild. - This will be `None` if no emojis are cached for this guild else - `typing.MutableSet[hikari.snowflakes.Snowflake]` of emoji IDs. + This will be [`None`][] if no emojis are cached for this guild. """ stickers: typing.Optional[typing.MutableSet[snowflakes.Snowflake]] = attrs.field(default=None) """A sequence of sticker IDs cached for this guild. - This will be `None` if no stickers are cached for this guild else - `typing.Sequence[hikari.snowflakes.Snowflake]` of emoji IDs. + This will be [`None`][] if no stickers are cached for this guild. """ invites: typing.Optional[typing.MutableSequence[str]] = attrs.field(default=None) - """A set of the `str` codes of the invites cached for this guild. + """A set of the [`str`][] codes of the invites cached for this guild. - This will be `None` if no invites are cached for this guild else - `typing.MutableSequence[str]` of invite codes. + This will be [`None`][] if no invites are cached for this guild. """ members: typing.Optional[collections.ExtendedMutableMapping[snowflakes.Snowflake, RefCell[MemberData]]] = ( @@ -230,8 +225,7 @@ class GuildRecord: ) """A mapping of user IDs to the objects of members cached for this guild. - This will be `None` if no members are cached for this guild else - `hikari.internal.collections.ExtendedMutableMapping[hikari.snowflakes.Snowflake, MemberData]`. + This will be [`None`][] if no members are cached for this guild. """ presences: typing.Optional[collections.ExtendedMutableMapping[snowflakes.Snowflake, MemberPresenceData]] = ( @@ -239,15 +233,13 @@ class GuildRecord: ) """A mapping of user IDs to objects of the presences cached for this guild. - This will be `None` if no presences are cached for this guild else - `hikari.internal.collections.ExtendedMutableMapping[hikari.snowflakes.Snowflake, MemberPresenceData]`. + This will be [`None`][] if no presences are cached for this guild. """ roles: typing.Optional[typing.MutableSet[snowflakes.Snowflake]] = attrs.field(default=None) """A set of the IDs of the roles cached for this guild. - This will be `None` if no roles are cached for this guild else - `typing.MutableSet[hikari.snowflakes.Snowflake]` of role IDs. + This will be [`None`][] if no roles are cached for this guild. """ voice_states: typing.Optional[collections.ExtendedMutableMapping[snowflakes.Snowflake, VoiceStateData]] = ( @@ -255,8 +247,7 @@ class GuildRecord: ) """A mapping of user IDs to objects of the voice states cached for this guild. - This will be `None` if no voice states are cached for this guild else - `hikari.internal.collections.ExtendedMutableMapping[hikari.snowflakes.Snowflake, VoiceStateData]`. + This will be [`None`][] if no voice states are cached for this guild. """ def empty(self) -> bool: @@ -285,7 +276,7 @@ def empty(self) -> bool: class BaseData(abc.ABC, typing.Generic[ValueT]): """A data class used for in-memory storage of entities in a more primitive form. - .. note:: + !!! note This base implementation assumes that all the fields it'll handle will be immutable and to handle mutable fields you'll have to override build_entity and build_from_entity to explicitly copy them. @@ -998,7 +989,7 @@ def copy(self) -> ValueT: def unwrap_ref_cell(cell: RefCell[ValueT]) -> ValueT: - """Unwrap a `RefCell` instance to it's contents. + """Unwrap a [`RefCell`][] instance to it's contents. Parameters ---------- diff --git a/hikari/internal/collections.py b/hikari/internal/collections.py index 83df4ee983..0588a58339 100644 --- a/hikari/internal/collections.py +++ b/hikari/internal/collections.py @@ -68,12 +68,12 @@ class ExtendedMutableMapping(typing.MutableMapping[KeyT, ValueT], abc.ABC): def copy(self) -> Self: """Return a copy of this mapped collection. - Unlike simply doing `dict(mapping)`, this may rely on internal detail + Unlike simply doing [dict(mapping)][], this may rely on internal detail around how the data is being stored to allow for a more efficient copy. - This may look like calling `dict.copy` and wrapping the result in a + This may look like calling [`dict.copy`][] and wrapping the result in a mapped collection. - .. note:: + !!! note Any removal policy on this mapped collection will be copied over. Returns @@ -86,12 +86,12 @@ def copy(self) -> Self: def freeze(self) -> typing.MutableMapping[KeyT, ValueT]: """Return a frozen mapping view of the items in this mapped collection. - Unlike simply doing `dict(mapping)`, this may rely on internal detail + Unlike simply doing [dict(mapping)][], this may rely on internal detail around how the data is being stored to allow for a more efficient copy. - This may look like calling `dict.copy`. + This may look like calling [`dict.copy`][]. - .. note:: - Unlike `ExtendedMutableMapping.copy`, this should return a pure + !!! note + Unlike [`ExtendedMutableMapping.copy`][], this should return a pure mapping with no removal policy at all. Returns @@ -151,7 +151,7 @@ class LimitedCapacityCacheMap(ExtendedMutableMapping[KeyT, ValueT]): on_expire : typing.Optional[typing.Callable[[ValueT], None]] A function to call each time an item is garbage collected from this map. This should take one positional argument of the same type stored - in this mapping as the value and should return `None`. + in this mapping as the value and should return [`None`][]. This will always be called after the entry has been removed. """ @@ -206,7 +206,7 @@ def __setitem__(self, key: KeyT, value: ValueT) -> None: # TODO: can this be immutable? class SnowflakeSet(typing.MutableSet[snowflakes.Snowflake]): - r"""Set of `hikari.snowflakes.Snowflake` objects. + r"""Set of [`hikari.snowflakes.Snowflake`][] objects. This internally uses a sorted bisect-array of 64 bit integers to represent the information. This reduces the space needed to store these objects @@ -224,12 +224,12 @@ class SnowflakeSet(typing.MutableSet[snowflakes.Snowflake]): will be $$ \mathcal{O} \left( \log n \right) $$ Insertions and removals will take $$ \mathcal{O} \left( \log n \right) $$ - operations in the worst case, due to `bisect` using a binary insertion sort + operations in the worst case, due to [`bisect`][] using a binary insertion sort algorithm internally. Average case will be $$ \mathcal{O} \left( \log n \right) $$ and best case will be $$ \Omega \left\( k \right) $$ - .. warning:: + !!! warning This is not thread-safe and must not be iterated across whilst being concurrently modified. @@ -264,7 +264,7 @@ def add_all(self, sfs: typing.Iterable[int], /) -> None: for sf in sfs: # Yes, this is repeated code, but we want insertions to be as fast # as possible for caching purposes, so reduce the number of function - # calls as much as possible and reimplement the logic for `add` + # calls as much as possible and reimplement the logic for [`add`][] # here. index = bisect.bisect_left(self._ids, sf) if index == len(self._ids): @@ -334,7 +334,7 @@ def get_index_or_slice( Raises ------ IndexError - If `index_or_slice` is an int and is outside the range of the mapping's + If [`index_or_slice`][] is an int and is outside the range of the mapping's contents. """ if isinstance(index_or_slice, slice): diff --git a/hikari/internal/data_binding.py b/hikari/internal/data_binding.py index 6d002e1f78..6314a664dc 100644 --- a/hikari/internal/data_binding.py +++ b/hikari/internal/data_binding.py @@ -78,15 +78,15 @@ JSONEncoder = typing.Callable[[typing.Union[JSONArray, JSONObject]], bytes] """Type hint for hikari-compatible JSON encoders. -A hikari-compatible JSON encoder is one which will take in a JSON-ish object and output either `str` -or `bytes`. +A hikari-compatible JSON encoder is one which will take in a JSON-ish object and output either [`str`][] +or [`bytes`][]. """ JSONDecoder = typing.Callable[[typing.Union[str, bytes]], typing.Union[JSONArray, JSONObject]] """Type hint for hikari-compatible JSON decoder. -A hikari-compatible JSON decoder is one which will take either a `str` or `bytes` and outputs -the JSON-ish object, as well as raises a `ValueError` on an incorrect JSON payload being passed in. +A hikari-compatible JSON decoder is one which will take either a [`str`][] or [`bytes`][] and outputs +the JSON-ish object, as well as raises a [`ValueError`][] on an incorrect JSON payload being passed in. """ _StringMapBuilderArg = typing.Union[ @@ -115,7 +115,7 @@ _json_separators = (",", ":") def default_json_dumps(obj: typing.Union[JSONArray, JSONObject]) -> bytes: - """Encode a JSON object to a `str`.""" + """Encode a JSON object to a [`str`][].""" return json.dumps(obj, separators=_json_separators).encode(_UTF_8) default_json_loads = json.loads @@ -131,7 +131,7 @@ def __init__(self, value: typing.Any, dumps: JSONEncoder = default_json_dumps) - @typing.final class URLEncodedFormBuilder: - """Helper class to generate `aiohttp.FormData`.""" + """Helper class to generate [`aiohttp.FormData`][].""" __slots__: typing.Sequence[str] = ("_fields", "_resources") @@ -167,15 +167,15 @@ async def build( class StringMapBuilder(multidict.MultiDict[str]): """Helper class used to quickly build query strings or header maps. - This will consume any items that are not `hikari.undefined.UNDEFINED`. + This will consume any items that are not [`hikari.undefined.UNDEFINED`][]. If a value is unspecified, it will be ignored when inserting it. This reduces the amount of boilerplate needed for generating the headers and query strings for low-level HTTP API interaction, amongst other things. - .. warning:: - Because this subclasses `dict`, you should not use the + !!! warning + Because this subclasses [`dict`][], you should not use the index operator to set items on this object. Doing so will skip any - form of validation on the type. Use the `put*` methods instead. + form of validation on the type. Use the [put*][] methods instead. """ __slots__: typing.Sequence[str] = () @@ -203,10 +203,10 @@ def put( ) -> None: """Add a key and value to the string map. - .. note:: - The value will always be cast to a `str` before inserting it. - `True` will be translated to `"true"`, `False` will be - translated to `"false"`, and `None` will be translated to + !!! note + The value will always be cast to a [`str`][] before inserting it. + [`True`][] will be translated to `"true"`, [`False`][] will be + translated to `"false"`, and [`None`][] will be translated to `"null"`. Parameters @@ -244,16 +244,16 @@ def put( class JSONObjectBuilder(typing.Dict[str, JSONish]): """Helper class used to quickly build JSON objects from various values. - If provided with any values that are `hikari.undefined.UNDEFINED`, + If provided with any values that are [`hikari.undefined.UNDEFINED`][], then these values will be ignored. This speeds up generation of JSON payloads for low level HTTP and websocket API interaction. - .. warning:: - Because this subclasses `dict`, you should not use the + !!! warning + Because this subclasses [`dict`][], you should not use the index operator to set items on this object. Doing so will skip any - form of validation on the type. Use the `put*` methods instead. + form of validation on the type. Use the [put*][] methods instead. """ __slots__: typing.Sequence[str] = () @@ -280,7 +280,7 @@ def put( ) -> None: """Put a JSON value. - If the value is `hikari.undefined.UNDEFINED` it will not be stored. + If the value is [`hikari.undefined.UNDEFINED`][] it will not be stored. Parameters ---------- @@ -327,7 +327,7 @@ def put_array( ) -> None: """Put a JSON array. - If the value is `hikari.undefined.UNDEFINED` it will not be stored. + If the value is [`hikari.undefined.UNDEFINED`][] it will not be stored. If provided, a conversion will be applied to each item. @@ -356,7 +356,7 @@ def put_snowflake( ) -> None: """Put a key with a snowflake value into the builder. - If the value is `hikari.undefined.UNDEFINED` it will not be stored. + If the value is [`hikari.undefined.UNDEFINED`][] it will not be stored. Parameters ---------- @@ -364,7 +364,7 @@ def put_snowflake( The key to give the element. value : hikari.undefined.UndefinedNoneOr[hikari.snowflakes.SnowflakeishOr[hikari.snowflakes.Unique]] The JSON type to put. This may alternatively be undefined, in this - case, nothing is performed. This may also be `None`, in this + case, nothing is performed. This may also be [`None`][], in this case the value isn't cast. """ if value is not undefined.UNDEFINED and value is not None: @@ -377,9 +377,9 @@ def put_snowflake_array( ) -> None: """Put an array of snowflakes with the given key into this builder. - If the value is `hikari.undefined.UNDEFINED` it will not be stored. + If the value is [`hikari.undefined.UNDEFINED`][] it will not be stored. - Each snowflake should be castable to an `int`. + Each snowflake should be castable to an [`int`][]. Parameters ---------- @@ -402,7 +402,7 @@ def cast_variants_array(cast: typing.Callable[[T_co], T], raw_values: typing.Ite Callback to cast each variant to. This will ignore any variants which raises - `hikari.errors.UnrecognisedEntityError` on cast. + [`hikari.errors.UnrecognisedEntityError`][] on cast. raw_values : typing.Iterable[T_co] Iterable of the raw values to cast. diff --git a/hikari/internal/deprecation.py b/hikari/internal/deprecation.py index cf7867cd04..7d369819e9 100644 --- a/hikari/internal/deprecation.py +++ b/hikari/internal/deprecation.py @@ -76,7 +76,7 @@ def warn_deprecated( stack_level : int The stack level to issue the warning in. quote : bool - Whether to quote `what` when displaying the deprecation + Whether to quote [`what`][] when displaying the deprecation Raises ------ diff --git a/hikari/internal/enums.py b/hikari/internal/enums.py index bff61dcbc9..63d154231e 100644 --- a/hikari/internal/enums.py +++ b/hikari/internal/enums.py @@ -20,7 +20,7 @@ # 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. -"""Implementation of parts of Python's `enum` protocol to be more performant.""" +"""Implementation of parts of Python's [`enum`][] protocol to be more performant.""" from __future__ import annotations __all__: typing.Sequence[str] = ("deprecated", "Enum", "Flag") @@ -99,7 +99,7 @@ def __setitem__(self, name: str, value: typing.Any) -> None: real_value = value.value if (alias := self.values_to_names.get(real_value)) is None: - raise ValueError("`deprecated` must be used on an existing value") + raise ValueError("[`deprecated`][] must be used on an existing value") member = _DeprecatedAlias(name, alias, value.removal_version) super().__setitem__(name, member) @@ -232,7 +232,7 @@ def __prepare__( return _EnumNamespace(object) try: - # Fails if Enum is not defined. We check this in `__new__` properly. + # Fails if Enum is not defined. We check this in [`__new__`][] properly. base, enum_type = bases if isinstance(base, _EnumMeta): @@ -249,17 +249,17 @@ def __repr__(cls) -> str: class Enum(metaclass=_EnumMeta): - """Clone of Python's `enum.Enum` implementation. + """Clone of Python's [`enum.Enum`][] implementation. This is designed to be faster and more efficient than Python's implementation, while retaining the majority of the external interface - that Python's `enum.Enum` provides. + that Python's [`enum.Enum`][] provides. - An `Enum` is a simple class containing a discrete set of constant values - that can be used in place of this type. This acts as a type-safe way - of representing a set number of "things". + An [`hikari.internal.enums.Enum`][] is a simple class containing a discrete set + of constant values that can be used in place of this type. This acts as a + type-safe way of representing a set number of "things". - .. warning:: + !!! warning Some semantics such as subtype checking and instance checking may differ. It is recommended to compare these values using the `==` operator rather than the `is` operator for safety reasons. @@ -269,55 +269,55 @@ class Enum(metaclass=_EnumMeta): * `__enumtype__` : Always `Enum`. * `__members__` : - An immutable `typing.Mapping` that maps each member name to the member + An immutable [`typing.Mapping`][] that maps each member name to the member value. - * ` __objtype__` : + * `__objtype__` : Always the first type that the enum is derived from. For example: - .. code-block:: python - + ```py >>> class UserType(str, Enum): ... USER = "user" ... PARTIAL = "partial" ... MEMBER = "member" >>> print(UserType.__objtype__) + ``` Operators on the class ---------------------- * `EnumType["FOO"]` : - Return the member that has the name `FOO`, raising a `KeyError` + Return the member that has the name `FOO`, raising a [`KeyError`][] if it is not present. * `EnumType.FOO` : Return the member that has the name `FOO`, raising a - `AttributeError` if it is not present. + [`AttributeError`][] if it is not present. * `EnumType(x)` : Attempt to cast `x` to the enum type by finding an existing member that has the same __value__. If this fails, you should expect a - `ValueError` to be raised. + [`ValueError`][] to be raised. Operators on each enum member ----------------------------- - * `e1 == e2` : `bool` + * `e1 == e2` : [`bool`][] Compare equality. - * `e1 != e2` : `bool` + * `e1 != e2` : [`bool`][] Compare inequality. - * `repr(e)` : `str` + * `repr(e)` : [`str`][] Get the machine readable representation of the enum member `e`. - * `str(e)` : `str` - Get the `str` name of the enum member `e`. + * `str(e)` : [`str`][] + Get the [`str`][] name of the enum member `e`. Special properties on each enum member -------------------------------------- - * `name` : `str` + * `name` : [`str`][] The name of the member. * `value` : The value of the member. The type depends on the implementation type of the enum you are using. All other methods and operators on enum members are inherited from the - member's __value__. For example, an enum extending `int` would - be able to be used as an `int` type outside these overridden definitions. + member's __value__. For example, an enum extending [`int`][] would + be able to be used as an [`int`][] type outside these overridden definitions. """ _name_to_member_map_: typing.ClassVar[typing.Mapping[str, Enum]] @@ -331,7 +331,7 @@ class Enum(metaclass=_EnumMeta): @property def name(self) -> str: - """Return the name of the enum member as a `str`.""" + """Return the name of the enum member as a [`str`][].""" return self._name_ @property @@ -508,22 +508,22 @@ def __repr__(cls) -> str: class Flag(metaclass=_FlagMeta): - """Clone of Python's `enum.Flag` implementation. + """Clone of Python's [`enum.Flag`][] implementation. This is designed to be faster and more efficient than Python's implementation, while retaining the majority of the external interface - that Python's `enum.Flag` provides. + that Python's [`enum.Flag`][] provides. - In simple terms, an `Flag` is a set of wrapped constant `int` + In simple terms, a flag is a set of wrapped constant [`int`][] values that can be combined in any combination to make a special value. This is a more efficient way of combining things like permissions together into a single integral value, and works by setting the individual `1` and `0` on the binary representation of the integer. This implementation has extra features, in that it will actively behave - like a `set` as well. + like a [`set`][] as well. - .. warning:: + !!! warning It is important to keep in mind that some semantics such as subtype checking and instance checking may differ. It is recommended to compare these values using the `==` operator rather than the `is` operator for @@ -536,29 +536,29 @@ class Flag(metaclass=_FlagMeta): Failing to observe this __will__ result in unexpected behaviour occurring in your application! - Also important to note is that despite wrapping `int` values, - conceptually this does not behave as if it were a subclass of `int`. + Also important to note is that despite wrapping [`int`][] values, + conceptually this does not behave as if it were a subclass of [`int`][]. Special Members on the class ---------------------------- * `__enumtype__` : - Always `Flag`. + Always [`Flag`][]. * `__everything__` : A special member with all documented bits set. * `__members__` : - An immutable `typing.Mapping` that maps each member name to the member + An immutable [`typing.Mapping`][] that maps each member name to the member value. - * ` __objtype__` : - Always `int`. + * `__objtype__` : + Always [`int`][]. Operators on the class ---------------------- * `FlagType["FOO"]` : - Return the member that has the name `FOO`, raising a `KeyError` + Return the member that has the name `FOO`, raising a [`KeyError`][] if it is not present. * `FlagType.FOO` : Return the member that has the name `FOO`, raising a - `AttributeError` if it is not present. + [`AttributeError`][] if it is not present. * `FlagType(x)` : Attempt to cast `x` to the enum type by finding an existing member that has the same __value__. If this fails, then a special __composite__ @@ -570,17 +570,17 @@ class Flag(metaclass=_FlagMeta): * `e1 & e2` : Bitwise `AND` operation. Will return a member that contains all flags that are common between both operands on the values. This also works with - one of the operands being an `int`eger. You may instead use + one of the operands being an [`int`][]eger. You may instead use the `intersection` method. * `e1 | e2` : Bitwise `OR` operation. Will return a member that contains all flags that appear on at least one of the operands. This also works with - one of the operands being an `int`eger. You may instead use + one of the operands being an [`int`][]eger. You may instead use the `union` method. * `e1 ^ e2` : Bitwise `XOR` operation. Will return a member that contains all flags that only appear on at least one and at most one of the operands. - This also works with one of the operands being an `int`eger. + This also works with one of the operands being an [`int`][]. You may instead use the `symmetric_difference` method. * `~e` : Return the inverse of this value. This is equivalent to disabling all @@ -591,11 +591,11 @@ class Flag(metaclass=_FlagMeta): Bitwise set difference operation. Returns all flags set on `e1` that are not set on `e2` as well. You may instead use the `difference` method. - * `bool(e)` : `bool` - Return `True` if `e` has a non-zero value, otherwise - `False`. - * `E.A in e`: `bool` - `True` if `E.A` is in `e`. This is functionally equivalent + * `bool(e)` : [`bool`][] + Return [`True`][] if `e` has a non-zero value, otherwise + [`False`][]. + * `E.A in e`: [`bool`][] + [`True`][] if `E.A` is in `e`. This is functionally equivalent to `E.A & e == E.A`. * `iter(e)` : Explode the value into a iterator of each __documented__ flag that can @@ -605,38 +605,38 @@ class Flag(metaclass=_FlagMeta): powers of two (this means if converted to twos-compliment binary, exactly one bit must be a `1`). In simple terms, this means that you should not expect combination flags to be returned. - * `e1 == e2` : `bool` + * `e1 == e2` : [`bool`][] Compare equality. - * `e1 != e2` : `bool` + * `e1 != e2` : [`bool`][] Compare inequality. - * `e1 < e2` : `bool` + * `e1 < e2` : [`bool`][] Compare by ordering. - * `int(e)` : `int` + * `int(e)` : [`int`][] Get the integer value of this flag - * `repr(e)` : `str` + * `repr(e)` : [`str`][] Get the machine readable representation of the flag member `e`. - * `str(e)` : `str` - Get the `str` name of the flag member `e`. + * `str(e)` : [`str`][] + Get the [`str`][] name of the flag member `e`. Special properties on each flag member -------------------------------------- - * `e.name` : `str` + * `e.name` : [`str`][] The name of the member. For composite members, this will be generated. - * `e.value` : `int` + * `e.value` : [`int`][] The value of the member. Special members on each flag member ----------------------------------- - * `e.all(E.A, E.B, E.C, ...)` : `bool` - Returns `True` if __all__ of `E.A`, `E.B`, `E.C`, et cetera + * `e.all(E.A, E.B, E.C, ...)` : [`bool`][] + Returns [`True`][] if __all__ of `E.A`, `E.B`, `E.C`, et cetera make up the value of `e`. - * `e.any(E.A, E.B, E.C, ...)` : `bool` - Returns `True` if __any__ of `E.A`, `E.B`, `E.C`, et cetera + * `e.any(E.A, E.B, E.C, ...)` : [`bool`][] + Returns [`True`][] if __any__ of `E.A`, `E.B`, `E.C`, et cetera make up the value of `e`. - * `e.none(E.A, E.B, E.C, ...)` : `bool` - Returns `True` if __none__ of `E.A`, `E.B`, `E.C`, et cetera + * `e.none(E.A, E.B, E.C, ...)` : [`bool`][] + Returns [`True`][] if __none__ of `E.A`, `E.B`, `E.C`, et cetera make up the value of `e`. - * `e.split()` : `typing.Sequence` + * `e.split()` : [`typing.Sequence`][] Explode the value into a sequence of each __documented__ flag that can be combined to make up the value `e`. Returns a sorted sequence of each power-of-two flag that makes up the value `e`. This is equivalent to @@ -645,7 +645,7 @@ class Flag(metaclass=_FlagMeta): All other methods and operators on `Flag` members are inherited from the member's __value__. - .. note:: + !!! note Due to limitations around how this is re-implemented, this class is not considered a subclass of `Enum` at runtime, even if MyPy believes this is possible @@ -664,14 +664,14 @@ class Flag(metaclass=_FlagMeta): @property def name(self) -> str: - """Return the name of the flag combination as a `str`.""" + """Return the name of the flag combination as a [`str`][].""" if self._name_ is None: self._name_ = "|".join(_name_resolver(self._value_to_member_map_, self._value_)) return self._name_ @property def value(self) -> int: - """Return the `int` value of the flag.""" + """Return the [`int`][] value of the flag.""" return self._value_ def all(self, *flags: Self) -> bool: @@ -680,8 +680,8 @@ def all(self, *flags: Self) -> bool: Returns ------- bool - `True` if any of the given flags are part of this value. - Otherwise, return `False`. + [`True`][] if any of the given flags are part of this value. + Otherwise, return [`False`][]. """ return all((flag & self) == flag for flag in flags) @@ -691,8 +691,8 @@ def any(self, *flags: Self) -> bool: Returns ------- bool - `True` if any of the given flags are part of this value. - Otherwise, return `False`. + [`True`][] if any of the given flags are part of this value. + Otherwise, return [`False`][]. """ return any((flag & self) == flag for flag in flags) @@ -720,8 +720,8 @@ def is_disjoint(self, other: typing.Union[Self, 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`. + [`False`][]. If no common flag values exist between them, then + this returns [`True`][]. """ return not (self & other) @@ -739,14 +739,14 @@ def is_superset(self, other: typing.Union[Self, int]) -> bool: def none(self, *flags: Self) -> bool: """Check if none of the given flags are part of this value. - .. note:: - This is essentially the opposite of `Flag.any`. + !!! note + This is essentially the opposite of [`hikari.internal.enums.Flag.any`][]. Returns ------- bool - `True` if none of the given flags are part of this value. - Otherwise, return `False`. + [`True`][] if none of the given flags are part of this value. + Otherwise, return [`False`][]. """ return not self.any(*flags) @@ -755,7 +755,7 @@ def split(self) -> typing.Sequence[Self]: Any unrecognised bits will be omitted for brevity. - The result will be a name-sorted `typing.Sequence` of each member + 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), diff --git a/hikari/internal/enums.pyi b/hikari/internal/enums.pyi index 79af942f7f..7227ac047f 100644 --- a/hikari/internal/enums.pyi +++ b/hikari/internal/enums.pyi @@ -20,7 +20,7 @@ # 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. -"""Typehints for `hikari.internal.enums`.""" +"""Typehints for [`hikari.internal.enums`][].""" # Enums use a lot of internal voodoo that will not type check nicely, so we # skip that module with MyPy and just accept that "here be dragons". diff --git a/hikari/internal/fast_protocol.py b/hikari/internal/fast_protocol.py index 2e9f3b6f64..da6645b975 100644 --- a/hikari/internal/fast_protocol.py +++ b/hikari/internal/fast_protocol.py @@ -20,7 +20,7 @@ # 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. -"""A utility for faster `typing.Protocol` instance checks.""" +"""A utility for faster [`typing.Protocol`][] instance checks.""" from __future__ import annotations @@ -39,7 +39,7 @@ def _check_if_ignored(name: str) -> bool: return name.startswith("_abc_") or name in _IGNORED_ATTRS -# This metaclass needs to subclass the same type as `typing.Protocol` to be +# This metaclass needs to subclass the same type as [`typing.Protocol`][] to be # able to overwrite it class _FastProtocolChecking(type(typing.Protocol)): _attributes_: typing.Tuple[str, ...] @@ -102,9 +102,9 @@ def __instancecheck__(self, other: typing.Any) -> bool: class FastProtocolChecking(typing.Protocol, metaclass=_FastProtocolChecking): """An extension to make protocols with faster instance checks. - .. note:: + !!! note All protocols that subclass this class must be decorated with - `@typing.runtime_checkable` to keep mypy happy. + [@typing.runtime_checkable][] to keep mypy happy. """ __slots__: typing.Sequence[str] = () diff --git a/hikari/internal/mentions.py b/hikari/internal/mentions.py index 6494e9203f..0c6d32a736 100644 --- a/hikari/internal/mentions.py +++ b/hikari/internal/mentions.py @@ -48,17 +48,17 @@ def generate_allowed_mentions( ---------- mentions_everyone : hikari.undefined.UndefinedOr[bool] Whether @everyone and @here mentions are enabled. If - `hikari.undefined.UNDEFINED` or `False` then this will be disabled. + [`hikari.undefined.UNDEFINED`][] or [`False`][] then this will be disabled. mentions_reply : hikari.undefined.UndefinedOr[bool] - Whether the reply mention should be enabled. If `hikari.undefined.UNDEFINED` - or `False` then this will be disabled. + Whether the reply mention should be enabled. If [`hikari.undefined.UNDEFINED`][] + or [`False`][] then this will be disabled. user_mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.users.PartialUser], bool]] Either a sequence of objects/IDs of the users to enabled mentions for, - `True` to allow all mentions or `False`/`hikari.undefined.UNDEFINED` + [`True`][] to allow all mentions or [`False`][]/[`hikari.undefined.UNDEFINED`][] to disable all user mentions. role_mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.guilds.PartialRole], bool]] Either a sequence of objects/IDs of the roles to enabled mentions for, - `True` to allow all mentions or `False`/`hikari.undefined.UNDEFINED` + [`True`][] to allow all mentions or [`False`][]/[`hikari.undefined.UNDEFINED`][] to disable all user mentions. Returns diff --git a/hikari/internal/net.py b/hikari/internal/net.py index 8ec6aeb817..fea8f26bcd 100644 --- a/hikari/internal/net.py +++ b/hikari/internal/net.py @@ -89,10 +89,10 @@ def create_tcp_connector( Optional Parameters ------------------- dns_cache : typing.Union[None, bool, int] - If `True`, DNS caching is used with a default TTL of 10 seconds. - If `False`, DNS caching is disabled. If an `int` is + If [`True`][], DNS caching is used with a default TTL of 10 seconds. + If [`False`][], DNS caching is disabled. If an [`int`][] is given, then DNS caching is enabled with an explicit TTL set. If - `None`, the cache will be enabled and never invalidate. + [`None`][], the cache will be enabled and never invalidate. limit : int Number of connections to allow in the pool at any given time. @@ -120,10 +120,10 @@ def create_client_session( ) -> aiohttp.ClientSession: """Generate a client session using the given settings. - .. warning:: + !!! warning You must invoke this from within a running event loop. - .. note:: + !!! note If you pass an explicit connector, then the connection that is created will not own the connector. You will be expected to manually close it __after__ the returned @@ -134,16 +134,15 @@ def create_client_session( connector : aiohttp.BaseConnector The connector to use. connector_owner : bool - If `True`, then the client session will close the + If [`True`][], then the client session will close the connector on shutdown. Otherwise, you must do it manually. http_settings : hikari.impl.config.HTTPSettings HTTP settings to use. raise_for_status : bool - `True` to default to throwing exceptions if a request - fails, or `False` to default to not. + Whether to raise an exception when a request fails trust_env : bool - `True` to trust anything in environment variables - and the `netrc` file, `False` to ignore it. + Whether to trust anything in environment variables + and the `netrc` file. Returns ------- diff --git a/hikari/internal/reflect.py b/hikari/internal/reflect.py index f8d6b58c6e..41e353b6f5 100644 --- a/hikari/internal/reflect.py +++ b/hikari/internal/reflect.py @@ -35,14 +35,14 @@ _T = typing.TypeVar("_T") EMPTY: typing.Final[typing.Any] = inspect.Parameter.empty -"""A singleton that empty annotations will be set to in `resolve_signature`.""" +"""A singleton that empty annotations will be set to in [`resolve_signature`][].""" def resolve_signature(func: typing.Callable[..., typing.Any]) -> inspect.Signature: - """Get the `inspect.Signature` of `func` with resolved forward annotations. + """Get the [`inspect.Signature`][] of `func` with resolved forward annotations. - .. warning:: - This will use `eval` to resolve string type-hints and forward + !!! warning + This will use [`eval`][] to resolve string type-hints and forward references. This has a slight performance overhead, so attempt to cache this info as much as possible. @@ -54,7 +54,7 @@ def resolve_signature(func: typing.Callable[..., typing.Any]) -> inspect.Signatu Returns ------- inspect.Signature - A `inspect.Signature` object with all forward reference annotations + A [`inspect.Signature`][] object with all forward reference annotations resolved. """ if sys.version_info >= (3, 10): @@ -84,7 +84,7 @@ def profiled(call: typing.Callable[..., _T]) -> typing.Callable[..., _T]: # pra Profile results are dumped to stdout. - .. warning:: + !!! warning This is NOT part of the public API. It should be considered to be internal detail and will likely be removed without prior warning in the future. You have been warned! diff --git a/hikari/internal/routes.py b/hikari/internal/routes.py index 0db58bbfe2..6174720024 100644 --- a/hikari/internal/routes.py +++ b/hikari/internal/routes.py @@ -55,8 +55,8 @@ class CompiledRoute: """A compiled representation of a route to a specific resource. - This is a similar representation to what `Route` provides, except - `Route` is treated as a template, this is treated as an instance. + This is a similar representation to what [`Route`][] provides, except + [`Route`][] is treated as a template, this is treated as an instance. """ major_param_hash: str = attrs.field() @@ -143,7 +143,7 @@ class Route: has_ratelimits: bool = attrs.field(hash=False, eq=False, repr=False) """Whether this route is affected by ratelimits. - This should be left as `True` (the default) for most routes. This + This should be left as [`True`][] (the default) for most routes. This only covers specific routes where no ratelimits exist, so we can be a bit more efficient with them. """ @@ -161,7 +161,7 @@ def __init__(self, method: str, path_template: str, *, has_ratelimits: bool = Tr break def compile(self, **kwargs: typing.Any) -> CompiledRoute: - """Generate a formatted `CompiledRoute` for this route. + """Generate a formatted [`CompiledRoute`][] for this route. This takes into account any URL parameters that have been passed. @@ -228,7 +228,7 @@ def compile( file_format : str The file format to use for the asset. size : typing.Optional[int] - The custom size query parameter to set. If `None`, + The custom size query parameter to set. If [`None`][], it is not passed. **kwargs : typing.Any Parameters to interpolate into the path template. @@ -282,7 +282,7 @@ def compile( def compile_to_file( self, base_url: str, *, file_format: str, size: typing.Optional[int] = None, **kwargs: typing.Any ) -> files.URL: - """Perform the same as `compile`, but return the URL as a `files.URL`.""" + """Perform the same as `compile`, but return the URL as a [`hikari.files.URL`][].""" return files.URL(self.compile(base_url, file_format=file_format, size=size, **kwargs)) diff --git a/hikari/internal/signals.py b/hikari/internal/signals.py index 11dcfdca13..6e74856dc9 100644 --- a/hikari/internal/signals.py +++ b/hikari/internal/signals.py @@ -87,7 +87,7 @@ def handle_interrupts( enabled : typing.Optional[bool] Whether to enable the signal interrupts. - If set to `None`, then it will be enabled or not based on whether the running + If set to [`None`][], then it will be enabled or not based on whether the running thread is the main one or not. loop : asyncio.AbstractEventLoop The event loop the interrupt will be raised in. diff --git a/hikari/internal/spel.py b/hikari/internal/spel.py index 4d7d94ac4c..891a9f30ef 100644 --- a/hikari/internal/spel.py +++ b/hikari/internal/spel.py @@ -34,9 +34,9 @@ For applying `"bar.baz"` to `foo`, we assume `bar` is an attribute or property of `foo`, and `baz` is an attribute or property of `foo.bar`. We may instead -want to invoke a method that takes no parameters (looking at `str.islower`, as +want to invoke a method that takes no parameters (looking at [`str.islower`][], as an example. To do this, we append `()` onto the attribute name. For example, -applying `author.username.islower()` to a `hikari.messages.Message` +applying `author.username.islower()` to a [`hikari.messages.Message`][] object. All expressions may start with a ``.``. You can negate the whole expression @@ -44,8 +44,9 @@ You may also want to negate a condition. To do this, prepend `!` to the attribute name. For example, to check if a message was not made by a bot, -you could run `author.!is_bot` on a `Message` object. Likewise, to check if -the input was not a number, you could run `content.!isdigit()`. +you could run `author.!is_bot` on a [`hikari.messages.Message`][] object. +Likewise, to check if the input was not a number, you could run +`content.!isdigit()`. This expression language is highly experimental and may change without prior notice for the time being. @@ -65,7 +66,7 @@ class AttrGetter(typing.Generic[InputValueT, ReturnValueT]): """An attribute getter that can resolve nested attributes and methods. This follows the SPEL definition for how to define expressions. Expressions - may be preceded with an optional ``.`` to aid in readability. + may be preceded with an optional `.` to aid in readability. """ __slots__: typing.Sequence[str] = ("pipeline", "invert_all") diff --git a/hikari/internal/time.py b/hikari/internal/time.py index bf7d4bc760..51ea6be58f 100644 --- a/hikari/internal/time.py +++ b/hikari/internal/time.py @@ -48,8 +48,8 @@ This is a type that is like an interval of some sort. -This is an alias for `typing.Union[int, float, datetime.datetime]`, -where `int` and `float` types are interpreted as a number of seconds. +This is an alias for [typing.Union[int, float, datetime.datetime]][], +where [`int`][] and [`float`][] types are interpreted as a number of seconds. """ DISCORD_EPOCH: typing.Final[datetime.timedelta] = datetime.timedelta(seconds=1_420_070_400) @@ -106,23 +106,23 @@ def slow_iso8601_datetime_string_to_datetime(datetime_str: str) -> datetime.date def discord_epoch_to_datetime(epoch: int, /) -> datetime.datetime: - """Parse a Discord epoch into a `datetime.datetime` object. + """Parse a Discord epoch into a [`datetime.datetime`][] object. Parameters ---------- epoch : int - Number of milliseconds since `1/1/2015 00:00:00 UTC`. + Number of milliseconds since [1/1/2015 00:00:00 UTC][]. Returns ------- datetime.datetime - Number of seconds since `1/1/1970 00:00:00 UTC`. + Number of seconds since [1/1/1970 00:00:00 UTC][]. """ return datetime.datetime.fromtimestamp(epoch / 1_000, datetime.timezone.utc) + DISCORD_EPOCH def datetime_to_discord_epoch(timestamp: datetime.datetime) -> int: - """Parse a `datetime.datetime` object into an `int` `DISCORD_EPOCH` offset. + """Parse a [`datetime.datetime`][] object into an [`int`][] `DISCORD_EPOCH` offset. Parameters ---------- @@ -138,25 +138,25 @@ def datetime_to_discord_epoch(timestamp: datetime.datetime) -> int: def unix_epoch_to_datetime(epoch: typing.Union[int, float], /, *, is_millis: bool = True) -> datetime.datetime: - """Parse a UNIX epoch to a `datetime.datetime` object. + """Parse a UNIX epoch to a [`datetime.datetime`][] object. - .. note:: + !!! note If an epoch that's outside the range of what this system can handle, - this will return `datetime.datetime.max` if the timestamp is positive, - or `datetime.datetime.min` otherwise. + this will return [`datetime.datetime.max`][] if the timestamp is positive, + or [`datetime.datetime.min`][] otherwise. Parameters ---------- epoch : typing.Union[int, float] - Number of seconds/milliseconds since `1/1/1970 00:00:00 UTC`. + Number of seconds/milliseconds since [1/1/1970 00:00:00 UTC][]. is_millis : bool - `True` by default, indicates the input timestamp is measured in + [`True`][] by default, indicates the input timestamp is measured in milliseconds rather than seconds. Returns ------- datetime.datetime - Number of seconds since `1/1/1970 00:00:00 UTC`. + Number of seconds since [1/1/1970 00:00:00 UTC][]. """ # Datetime seems to raise an OSError when you try to convert an out of range timestamp on Windows and a ValueError # if you try on a UNIX system so we want to catch both. diff --git a/hikari/internal/ux.py b/hikari/internal/ux.py index 08738bc125..cd60ddc657 100644 --- a/hikari/internal/ux.py +++ b/hikari/internal/ux.py @@ -75,13 +75,13 @@ def init_logging( ) -> None: """Initialize logging for the user. - .. note:: + !!! note If any handlers already exist, some opinionated defaults will be configured (mostly do to with logging efficiency and warning logging), but existing handlers will not be overwritten. You can disable this by passing - `None` as the `flavor` parameter. + [`None`][] as the `flavor` parameter. - .. warning:: + !!! warning This function is blocking! Parameters @@ -89,53 +89,50 @@ def init_logging( flavor : typing.Optional[None, str, int, typing.Dict[str, typing.Any], os.PathLike[str]] The hint for configuring logging. - This can be `None` to not enable logging automatically. + This can be [`None`][] to not enable logging automatically. - If you pass a `str` or a `int`, it is interpreted as + If you pass a [`str`][] or a [`int`][], it is interpreted as the global logging level to use, and should match one of `"DEBUG"`, `"INFO"`, `"WARNING"`, `"ERROR"` or `"CRITICAL"`. The configuration will be set up to use a `colorlog` coloured logger, and to use a sane logging format strategy. The output will be written - to `sys.stdout` using this configuration. + to [`sys.stdout`][] using this configuration. - If you pass a `dict`, it is treated as the mapping to pass to - `logging.config.dictConfig`. If the dict defines any handlers, default + If you pass a [`dict`][], it is treated as the mapping to pass to + [`logging.config.dictConfig`][]. If the dict defines any handlers, default handlers will not be setup if `incremental` is not specified. - If you pass a `str` to an existing file or a `os.PathLike`, it is - interpreted as the file to load config from using `logging.config.fileConfig`. + If you pass a [`str`][] to an existing file or a [`os.PathLike`][], it is + interpreted as the file to load config from using [`logging.config.fileConfig`][]. Note that `"TRACE_HIKARI"` is a library-specific logging level which is expected to be more verbose than `"DEBUG"`. allow_color : bool - If `False`, no colour is allowed. If `True`, the - output device must be supported for this to return `True`. + If [`False`][], no colour is allowed. If [`True`][], the + output device must be supported for colour to be enabled. force_color : bool - If `True`, return `True` always, otherwise only - return `True` if the device supports colour output and the - `allow_color` flag is not `False`. + If [`True`][], always force colour. Examples -------- Simple logging setup: - .. code-block:: python - + ```py init_logging("INFO") # Registered logging level # or init_logging(20) # Logging level as an int + ``` File config: - .. code-block:: python - + ```py # See https://docs.python.org/3/library/logging.config.html#configuration-file-format for more info init_logging("path/to/file.ini") + ``` Setting up logging through a dict config: - .. code-block:: python - + ```py # See https://docs.python.org/3/library/logging.config.html#dictionary-schema-details for more info init_logging( { @@ -147,6 +144,7 @@ def init_logging( }, } ) + ``` """ # One observation that has been repeatedly made from seeing beginners writing # bots in Python is that most people seem to have no idea what logging is or @@ -252,7 +250,7 @@ def print_banner( force_color: bool, extra_args: typing.Optional[typing.Dict[str, str]] = None, ) -> None: - """Print a banner of choice to `sys.stdout`. + """Print a banner of choice to [`sys.stdout`][]. Inspired by Spring Boot, we display an ASCII logo on startup. This is styled to grab the user's attention, and contains info such as the library version, @@ -260,24 +258,22 @@ def print_banner( documentation. Users can override this by placing a `banner.txt` in some package and referencing it in this call. - .. note:: + !!! note The `banner.txt` must be in the root folder of the package. - .. warning:: + !!! warning This function is blocking! Parameters ---------- package : typing.Optional[str] - The package to find the `banner.txt` in, or `None` if no + The package to find the `banner.txt` in, or [`None`][] if no banner should be shown. allow_color : bool - If `False`, no colour is allowed. If `True`, the - output device must be supported for this to return `True`. + If [`False`][], no colour is allowed. If [`True`][], the + output device must be supported for colour to be enabled. force_color : bool - If `True`, return `True` always, otherwise only - return `True` if the device supports colour output and the - `allow_color` flag is not `False`. + If [`True`][], always force colour. extra_args : typing.Optional[typing.Dict[str, str]] If provided, extra $-substitutions to use when printing the banner. Default substitutions can not be overwritten. @@ -334,29 +330,29 @@ def warn_if_not_optimized(suppress: bool) -> None: if __debug__ and not suppress: _LOGGER.warning( "You are running on optimization level 0 (no optimizations), which may slow down your application. " - "For production, consider using at least level 1 optimization by passing `-O` to the python " + "For production, consider using at least level 1 optimization by passing [-O][] to the python " "interpreter call" ) def supports_color(allow_color: bool, force_color: bool) -> bool: - """Return `True` if the terminal device supports color output. + """Return [`True`][] if the terminal device supports color output. Parameters ---------- allow_color : bool - If `False`, no color is allowed. If `True`, the - output device must be supported for this to return `True`. + If [`False`][], no color is allowed. If [`True`][], the + output device must be supported for this to return [`True`][]. force_color : bool - If `True`, return `True` always, otherwise only - return `True` if the device supports color output and the - `allow_color` flag is not `False`. + If [`True`][], return [`True`][] always, otherwise only + return [`True`][] if the device supports color output and the + `allow_color` flag is not [`False`][]. Returns ------- bool - `True` if color is allowed on the output terminal, or - `False` otherwise. + [`True`][] if color is allowed on the output terminal, or + [`False`][] otherwise. """ if not allow_color: return False diff --git a/hikari/invites.py b/hikari/invites.py index 45646fd34e..8ead5162e2 100644 --- a/hikari/invites.py +++ b/hikari/invites.py @@ -103,16 +103,12 @@ class InviteGuild(guilds.PartialGuild): banner_hash: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) """The hash for the guild's banner. - This is only present if `hikari.guilds.GuildFeature.BANNER` is in the - `features` for this guild. For all other purposes, it is `None`. + This is only present if [`hikari.guilds.GuildFeature.BANNER`][] is in the + `features` for this guild. For all other purposes, it is [`None`][]. """ description: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) - """The guild's description. - - This is only present if certain `features` are set in this guild. - Otherwise, this will always be `None`. For all other purposes, it is `None`. - """ + """The guild's description.""" verification_level: typing.Union[guilds.GuildVerificationLevel, int] = attrs.field(eq=False, hash=False, repr=False) """The verification level required for a user to participate in this guild.""" @@ -120,8 +116,8 @@ class InviteGuild(guilds.PartialGuild): vanity_url_code: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=True) """The vanity URL code for the guild's vanity URL. - This is only present if `hikari.guilds.GuildFeature.VANITY_URL` is in the - `features` for this guild. If not, this will always be `None`. + This is only present if [`hikari.guilds.GuildFeature.VANITY_URL`][] is in the + `features` for this guild. If not, this will always be [`None`][]. """ welcome_screen: typing.Optional[guilds.WelcomeScreen] = attrs.field(eq=False, hash=False, repr=False) @@ -141,16 +137,16 @@ def make_splash_url(self, *, ext: str = "png", size: int = 4096) -> typing.Optio Parameters ---------- ext : str - The extension to use for this URL, defaults to `png`. - Supports `png`, `jpeg`, `jpg` and `webp`. + The extension to use for this URL. + supports `png`, `jpeg`, `jpg` and `webp`. size : int - The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- typing.Optional[hikari.files.URL] - The URL to the splash, or `None` if not set. + The URL to the splash, or [`None`][] if not set. Raises ------ @@ -175,20 +171,20 @@ def make_banner_url(self, *, ext: typing.Optional[str] = None, size: int = 4096) Parameters ---------- ext : typing.Optional[str] - The ext to use for this URL, defaults to `png` or `gif`. + The ext to use for this URL. Supports `png`, `jpeg`, `jpg`, `webp` and `gif` (when animated). - If `None`, then the correct default extension is + 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. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- typing.Optional[hikari.files.URL] - The URL of the banner, or `None` if no banner is set. + The URL of the banner, or [`None`][] if no banner is set. Raises ------ @@ -226,21 +222,21 @@ class Invite(InviteCode): guild: typing.Optional[InviteGuild] = attrs.field(eq=False, hash=False, repr=False) """The partial object of the guild this invite belongs to. - Will be `None` for group DM invites and when attached to a gateway event; - for invites received over the gateway you should refer to `Invite.guild_id`. + Will be [`None`][] for group DM invites and when attached to a gateway event; + for invites received over the gateway you should refer to [`hikari.invites.Invite.guild_id`][]. """ guild_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=True) """The ID of the guild this invite belongs to. - Will be `None` for group DM invites. + Will be [`None`][] for group DM invites. """ channel: typing.Optional[channels.PartialChannel] = attrs.field(eq=False, hash=False, repr=False) """The partial object of the channel this invite targets. - Will be `None` for invite objects that are attached to gateway events, - in which case you should refer to `Invite.channel_id`. + Will be [`None`][] for invite objects that are attached to gateway events, + in which case you should refer to [`hikari.invites.Invite.channel_id`][]. """ channel_id: snowflakes.Snowflake = attrs.field(eq=False, hash=False, repr=True) @@ -274,14 +270,14 @@ class Invite(InviteCode): """When this invite will expire. This field is only returned by the GET Invite REST endpoint and will be - returned as `None` by said endpoint if the invite doesn't have a set - expiry date. Other places will always return this as `None`. + returned as [`None`][] by said endpoint if the invite doesn't have a set + expiry date. Other places will always return this as [`None`][]. """ @attrs.define(hash=True, kw_only=True, weakref_slot=False) class InviteWithMetadata(Invite): - """Extends the base `Invite` object with metadata. + """Extends the base [`hikari.invites.Invite`][] object with metadata. The metadata is only returned when getting an invite with guild permissions, rather than it's code. @@ -293,7 +289,7 @@ class InviteWithMetadata(Invite): max_uses: typing.Optional[int] = attrs.field(eq=False, hash=False, repr=True) """The limit for how many times this invite can be used before it expires. - If set to `None` then this is unlimited. + If set to [`None`][] then this is unlimited. """ # TODO: can we use a non-None value to represent infinity here somehow, or @@ -301,7 +297,7 @@ class InviteWithMetadata(Invite): max_age: typing.Optional[datetime.timedelta] = attrs.field(eq=False, hash=False, repr=False) """The timedelta of how long this invite will be valid for. - If set to `None` then this is unlimited. + If set to [`None`][] then this is unlimited. """ is_temporary: bool = attrs.field(eq=False, hash=False, repr=True) @@ -313,14 +309,14 @@ class InviteWithMetadata(Invite): expires_at: typing.Optional[datetime.datetime] """When this invite will expire. - If this invite doesn't have a set expiry then this will be `None`. + If this invite doesn't have a set expiry then this will be [`None`][]. """ @property def uses_left(self) -> typing.Optional[int]: """Return the number of uses left for this invite. - This will be `None` if the invite has unlimited uses. + This will be [`None`][] if the invite has unlimited uses. """ if self.max_uses: return self.max_uses - self.uses diff --git a/hikari/iterators.py b/hikari/iterators.py index 49bb808f47..509691dac9 100644 --- a/hikari/iterators.py +++ b/hikari/iterators.py @@ -23,7 +23,7 @@ """Lazy iterators for data that requires repeated API calls to retrieve. For consumers of this API, the only class you need to worry about is -`LazyIterator`. Everything else is internal detail only exposed for people who +[`hikari.iterators.LazyIterator`][]. Everything else is internal detail only exposed for people who wish to extend this API further! """ from __future__ import annotations @@ -46,45 +46,45 @@ class All(typing.Generic[ValueT]): """Helper that wraps predicates and invokes them together. Calling this object will pass the input item to each item, returning - `True` only when all wrapped predicates return True when called + [`True`][] only when all wrapped predicates return True when called with the given item. For example... - .. code-block:: python - + ```py if w(foo) and x(foo) and y(foo) and z(foo): ... + ``` is equivalent to - .. code-block:: python - + ```py condition = All([w, x, y, z]) if condition(foo): ... + ``` - This behaves like a lazy wrapper implementation of the `all` builtin. + This behaves like a lazy wrapper implementation of the [`all`][] builtin. - .. note:: + !!! note Like the rest of the standard library, this is a short-circuiting - operation. This means that if a predicate returns `False`, no + operation. This means that if a predicate returns [`False`][], no predicates after this are invoked, as the result is already known. In this sense, they are invoked in-order. - .. warning:: + !!! warning You should not generally need to use this outside of extending the iterators API in this library! Operators --------- * `this(value : ValueT) -> bool`: - Return `True` if all conditions return `True` when + Return [`True`][] if all conditions return [`True`][] when invoked with the given value. * `~this`: Return a condition that, when invoked with the value, returns - `False` if all conditions were `True` in this object. + [`False`][] if all conditions were [`True`][] in this object. Parameters ---------- @@ -124,10 +124,10 @@ class AttrComparator(typing.Generic[ValueT]): Parameters ---------- attr_name : str - The attribute name. Can be prepended with a ``.`` optionally. + The attribute name. Can be prepended with a `.` optionally. If the attribute name ends with a `()`, then the call is invoked rather than treated as a property (useful for methods like - `str.isupper`, for example). + [`str.isupper`][], for example). expected_value : typing.Any The expected value. cast : typing.Optional[typing.Callable[[ValueT], typing.Any]] @@ -155,7 +155,7 @@ def __call__(self, item: ValueT) -> bool: class LazyIterator(typing.Generic[ValueT], abc.ABC): """A set of results that are fetched asynchronously from the API as needed. - This is a `typing.AsyncIterable` and `typing.AsyncIterator` with several + This is a [`typing.AsyncIterable`][] and [`typing.AsyncIterator`][] with several additional helpful methods provided for convenience. Examples @@ -164,50 +164,50 @@ class LazyIterator(typing.Generic[ValueT], abc.ABC): As an async iterable: - .. code-block:: python - + ```py >>> async for item in paginated_results: ... process(item) + ``` As an eagerly retrieved set of results (performs all API calls at once, which may be slow for large sets of data): - .. code-block:: python - + ```py >>> results = await paginated_results >>> # ... which is equivalent to this... >>> results = [item async for item in paginated_results] + ``` As an async iterator (not recommended): - .. code-block:: python - + ```py >>> try: ... while True: ... process(await paginated_results.__anext__()) ... except StopAsyncIteration: ... pass + ``` Additionally, you can make use of some of the provided helper methods on this class to perform basic operations easily. - Iterating across the items with indexes (like `enumerate` for normal + Iterating across the items with indexes (like [`enumerate`][] for normal iterables): - .. code-block:: python - + ```py >>> async for i, item in paginated_results.enumerate(): ... print(i, item) (0, foo) (1, bar) (2, baz) + ``` Limiting the number of results you iterate across: - .. code-block:: python - + ```py >>> async for item in paginated_results.limit(3): ... process(item) + ``` """ __slots__: typing.Sequence[str] = () @@ -223,7 +223,7 @@ def chunk(self, chunk_size: int) -> LazyIterator[typing.Sequence[ValueT]]: Returns ------- LazyIterator[typing.Sequence[ValueT]] - `LazyIterator` that emits each chunked sequence. + [`hikari.iterators.LazyIterator`][] that emits each chunked sequence. """ return _ChunkedLazyIterator(self, chunk_size) @@ -242,7 +242,7 @@ def map( Returns ------- LazyIterator[AnotherValueT] - `LazyIterator` that maps each value to another value. + [`hikari.iterators.LazyIterator`][] that maps each value to another value. """ if isinstance(transformation, str): transformation = typing.cast("spel.AttrGetter[ValueT, AnotherValueT]", spel.AttrGetter(transformation)) @@ -268,7 +268,7 @@ def filter( Each condition is treated as a predicate, being called with each item that this iterator would return when it is requested. - All conditions must evaluate to `True` for the item to be + All conditions must evaluate to [`True`][] for the item to be returned. If this is not met, then the item is discarded and ignored, the next matching item will be returned instead, if there is one. @@ -276,9 +276,9 @@ def filter( ---------- *predicates : typing.Union[typing.Callable[[ValueT], bool], typing.Tuple[str, typing.Any]] Predicates to invoke. These are functions that take a value and - return `True` if it is of interest, or `False` - otherwise. These may instead include 2-`tuple` objects - consisting of a `str` attribute name (nested attributes + return [`True`][] if it is of interest, or [`False`][] + otherwise. These may instead include 2-[`tuple`][] objects + consisting of a [`str`][] attribute name (nested attributes are referred to using the ``.`` operator), and values to compare for equality. This allows you to specify conditions such as `members.filter(("user.bot", True))`. @@ -289,7 +289,7 @@ def filter( Returns ------- LazyIterator[ValueT] - `LazyIterator` that only emits values where all conditions are + [`hikari.iterators.LazyIterator`][] that only emits values where all conditions are matched. """ conditions: All[ValueT] = self._map_predicates_and_attr_getters("filter", *predicates, **attrs) @@ -306,9 +306,9 @@ def take_while( ---------- *predicates : typing.Union[typing.Callable[[ValueT], bool], typing.Tuple[str, typing.Any]] Predicates to invoke. These are functions that take a value and - return `True` if it is of interest, or `False` - otherwise. These may instead include 2-`tuple` objects - consisting of a `str` attribute name (nested attributes + return [`True`][] if it is of interest, or [`False`][] + otherwise. These may instead include 2-[`tuple`][] objects + consisting of a [`str`][] attribute name (nested attributes are referred to using the ``.`` operator), and values to compare for equality. This allows you to specify conditions such as `members.take_while(("user.bot", True))`. @@ -336,9 +336,9 @@ def take_until( ---------- *predicates : typing.Union[typing.Callable[[ValueT], bool], typing.Tuple[str, typing.Any]] Predicates to invoke. These are functions that take a value and - return `True` if it is of interest, or `False` - otherwise. These may instead include 2-`tuple` objects - consisting of a `str` attribute name (nested attributes are + return [`True`][] if it is of interest, or [`False`][] + otherwise. These may instead include 2-[`tuple`][] objects + consisting of a [`str`][] attribute name (nested attributes are referred to using the ``.`` operator), and values to compare for equality. This allows you to specify conditions such as `members.take_until(("user.bot", True))`. @@ -368,9 +368,9 @@ def skip_while( ---------- *predicates : typing.Union[typing.Callable[[ValueT], bool], typing.Tuple[str, typing.Any]] Predicates to invoke. These are functions that take a value and - return `True` if it is of interest, or `False` - otherwise. These may instead include 2-`tuple` objects - consisting of a `str` attribute name (nested attributes + return [`True`][] if it is of interest, or [`False`][] + otherwise. These may instead include 2-[`tuple`][] objects + consisting of a [`str`][] attribute name (nested attributes are referred to using the ``.`` operator), and values to compare for equality. This allows you to specify conditions such as `members.skip_while(("user.bot", True))`. @@ -400,9 +400,9 @@ def skip_until( ---------- *predicates : typing.Union[typing.Callable[[ValueT], bool], typing.Tuple[str, typing.Any]] Predicates to invoke. These are functions that take a value and - return `True` if it is of interest, or `False` - otherwise. These may instead include 2-`tuple` objects - consisting of a `str` attribute name (nested attributes are + return [`True`][] if it is of interest, or [`False`][] + otherwise. These may instead include 2-[`tuple`][] objects + consisting of a [`str`][] attribute name (nested attributes are referred to using the ``.`` operator), and values to compare for equality. This allows you to specify conditions such as `members.skip_until(("user.bot", True))`. @@ -422,9 +422,9 @@ def skip_until( def enumerate(self, *, start: int = 0) -> LazyIterator[typing.Tuple[int, ValueT]]: """Enumerate the paginated results lazily. - This behaves as an asyncio-friendly version of `enumerate` + This behaves as an asyncio-friendly version of [`enumerate`][] which uses much less memory than collecting all the results first and - calling `enumerate` across them. + calling [`enumerate`][] across them. Parameters ---------- @@ -433,8 +433,7 @@ def enumerate(self, *, start: int = 0) -> LazyIterator[typing.Tuple[int, ValueT] Examples -------- - .. code-block:: python - + ```py >>> async for i, item in paginated_results.enumerate(): ... print(i, item) (0, foo) @@ -456,6 +455,7 @@ def enumerate(self, *, start: int = 0) -> LazyIterator[typing.Tuple[int, ValueT] (9, foo) (10, bar) (11, baz) + ``` Returns ------- @@ -475,10 +475,10 @@ def limit(self, limit: int) -> LazyIterator[ValueT]: Examples -------- - .. code-block:: python - + ```py >>> async for item in paginated_results.limit(3): ... print(item) + ``` Returns ------- @@ -525,7 +525,7 @@ async def next(self) -> ValueT: async def last(self) -> ValueT: """Return the last element of this iterator only. - .. note:: + !!! note This method will consume the whole iterator if run. Returns @@ -585,12 +585,12 @@ def flat_map(self, flattener: _FlattenerT[ValueT, AnotherValueT]) -> LazyIterato r"""Perform a flat mapping operation. This will pass each item in the iterator to the given `function` - parameter, expecting a new `typing.Iterable` or `typing.AsyncIterator` + parameter, expecting a new [`typing.Iterable`][] or [`typing.AsyncIterator`][] to be returned as the result. This means you can map to a new - `LazyIterator`, `typing.AsyncIterator`, `typing.Iterable`, + [`hikari.iterators.LazyIterator`][], [`typing.AsyncIterator`][], [`typing.Iterable`][], async generator, or generator. - Remember that `typing.Iterator` implicitly provides `typing.Iterable` + Remember that [`typing.Iterator`][] implicitly provides [`typing.Iterable`][] compatibility. This is used to provide lazy conversions, and can be used to implement @@ -610,8 +610,7 @@ def flat_map(self, flattener: _FlattenerT[ValueT, AnotherValueT]) -> LazyIterato The following example generates a distinct collection of all mentioned users in the given channel from the past 500 messages. - .. code-block:: python - + ```py def iter_mentioned_users(message: hikari.Message) -> typing.Iterable[Snowflake]: for match in re.findall(r"<@!?(\d+)>", message.content): yield Snowflake(match) @@ -624,6 +623,7 @@ def iter_mentioned_users(message: hikari.Message) -> typing.Iterable[Snowflake]: .flat_map(iter_mentioned_users) .distinct() ) + ``` Returns ------- @@ -639,19 +639,19 @@ def flatten(self: LazyIterator[typing.Iterable[AnotherValueT]]) -> LazyIterator[ def awaiting(self, window_size: int = 10) -> LazyIterator[ValueT]: """Await each item concurrently in a fixed size window. - .. warning:: + !!! warning Setting a large window size, or setting it to 0 to await everything is a dangerous thing to do if you are making API calls. Some endpoints will get ratelimited and cause a backup of waiting tasks, others may begin to spam global rate limits instead (the `fetch_user` endpoint seems to be notorious for doing this). - .. note:: + !!! note This call assumes that the iterator contains awaitable values as input. MyPy cannot detect this nicely, so any cast is forced internally. If the item is not awaitable, you will receive a - `TypeError` instead. + [`TypeError`][] instead. You have been warned. You cannot escape the ways of the duck type young grasshopper. @@ -749,13 +749,12 @@ class BufferedLazyIterator(typing.Generic[ValueT], LazyIterator[ValueT], abc.ABC thus reducing the amount of work needed if only a few objects out of, say, 100, need to be deserialized. - This `_next_chunk` should return `None` once the end of all items + This `_next_chunk` should return [`None`][] once the end of all items has been reached. An example would look like the following: - .. code-block:: python - + ```py async def some_http_call(i): ... @@ -775,6 +774,7 @@ def _next_chunk(self) -> typing.Optional[typing.Generator[ValueT, None, None]]: generator = (SomeObject(raw_item) for raw_item in raw_items) return generator + ``` """ __slots__: typing.Sequence[str] = ("_buffer",) diff --git a/hikari/messages.py b/hikari/messages.py index 97f66e8a85..fde2a63546 100644 --- a/hikari/messages.py +++ b/hikari/messages.py @@ -200,7 +200,7 @@ class MessageActivityType(int, enums.Enum): class Attachment(snowflakes.Unique, files.WebResource): """Represents a file attached to a message. - You can use this object in the same way as a `hikari.files.WebResource`, + You can use this object in the same way as a [`hikari.files.WebResource`][], by passing it as an attached file when creating a message, etc. It can also be used when editing a message to keep a previous attachment. @@ -295,7 +295,7 @@ class MessageReference: id: typing.Optional[snowflakes.Snowflake] = attrs.field(repr=True) """The ID of the original message. - This will be `None` for channel follow add messages. This may + This will be [`None`][] for channel follow add messages. This may point to a deleted message. """ @@ -305,7 +305,7 @@ class MessageReference: guild_id: typing.Optional[snowflakes.Snowflake] = attrs.field(repr=True) """The ID of the guild that the message originated from. - This will be `None` when the original message is not from + This will be [`None`][] when the original message is not from a guild. """ @@ -329,16 +329,16 @@ def make_cover_image_url(self, *, ext: str = "png", size: int = 4096) -> typing. Parameters ---------- ext : str - The extension to use for this URL, defaults to `png`. - Supports `png`, `jpeg`, `jpg` and `webp`. + The extension to use for this URL. + supports `png`, `jpeg`, `jpg` and `webp`. size : int - The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- typing.Optional[hikari.files.URL] - The URL, or `None` if no cover image exists. + The URL, or [`None`][] if no cover image exists. Raises ------ @@ -389,14 +389,13 @@ class PartialMessage(snowflakes.Unique): """A message representation containing partially populated information. This contains arbitrary fields that may be updated in a - `MessageUpdateEvent`, but for all other purposes should be treated as + [`hikari.events.message_events.MessageUpdateEvent`][], but for all other purposes should be treated as being optionally specified. - .. warning:: - All fields on this model except `channel` and `id` may be set to - `hikari.undefined.UNDEFINED` (a singleton) if we have not - received information about their state from Discord alongside field - nullability. + !!! warning + All fields on this model except `id` and `channel_id` may be set to + [`hikari.undefined.UNDEFINED`][] if we have not received information + about their state from Discord alongside field nullability. """ app: traits.RESTAware = attrs.field( @@ -411,30 +410,30 @@ class PartialMessage(snowflakes.Unique): """The ID of the channel that the message was sent in.""" guild_id: typing.Optional[snowflakes.Snowflake] = attrs.field(hash=False, eq=False, repr=True) - """The ID of the guild that the message was sent in or `None` for messages out of guilds. + """The ID of the guild that the message was sent in or [`None`][] for messages out of guilds. - .. warning:: - This will also be `None` for messages received from the REST API. + !!! warning + This will also be [`None`][] for messages received from the REST API. This is a Discord limitation as stated here """ author: undefined.UndefinedOr[users_.User] = attrs.field(hash=False, eq=False, repr=True) """The author of this message. - This will also be `hikari.undefined.UNDEFINED` in some cases such as when Discord + This will also be [`hikari.undefined.UNDEFINED`][] in some cases such as when Discord updates a message with an embed URL preview or in messages fetched from the REST API. """ member: undefined.UndefinedNoneOr[guilds.Member] = attrs.field(hash=False, eq=False, repr=False) """The member for the author who created the message. - If the message is not in a guild, this will be `None`. + If the message is not in a guild, this will be [`None`][]. - This will also be `hikari.undefined.UNDEFINED` in some cases such as when Discord + This will also be [`hikari.undefined.UNDEFINED`][] in some cases such as when Discord updates a message with an embed URL preview. - .. warning:: - This will also be `None` for messages received from the REST API. + !!! warning + This will also be [`None`][] for messages received from the REST API. This is a Discord limitation as stated here """ @@ -447,7 +446,7 @@ class PartialMessage(snowflakes.Unique): edited_timestamp: undefined.UndefinedNoneOr[datetime.datetime] = attrs.field(hash=False, eq=False, repr=False) """The timestamp that the message was last edited at. - Will be `None` if the message wasn't ever edited, or `undefined` + Will be [None] if the message wasn't ever edited, or [`hikari.undefined.UNDEFINED`][] if the info is not available. """ @@ -459,7 +458,7 @@ class PartialMessage(snowflakes.Unique): ) """Users who were notified by their mention in the message. - .. warning:: + !!! warning If the contents have not mutated and this is a message update event, some fields that are not affected may be empty instead. @@ -471,7 +470,7 @@ class PartialMessage(snowflakes.Unique): ) """IDs of roles that were notified by their mention in the message. - .. warning:: + !!! warning If the contents have not mutated and this is a message update event, some fields that are not affected may be empty instead. @@ -485,7 +484,7 @@ class PartialMessage(snowflakes.Unique): If the message is not crossposted, this will always be empty. - .. warning:: + !!! warning If the contents have not mutated and this is a message update event, some fields that are not affected may be empty instead. @@ -495,7 +494,7 @@ class PartialMessage(snowflakes.Unique): mentions_everyone: undefined.UndefinedOr[bool] = attrs.field(hash=False, eq=False, repr=False) """Whether the message notifies using `@everyone` or `@here`. - .. warning:: + !!! warning If the contents have not mutated and this is a message update event, some fields that are not affected may be empty instead. @@ -523,7 +522,7 @@ class PartialMessage(snowflakes.Unique): activity: undefined.UndefinedNoneOr[MessageActivity] = attrs.field(hash=False, eq=False, repr=False) """The message activity. - .. note:: + !!! note This will only be provided for messages with rich-presence related chat embeds. """ @@ -531,7 +530,7 @@ class PartialMessage(snowflakes.Unique): application: undefined.UndefinedNoneOr[MessageApplication] = attrs.field(hash=False, eq=False, repr=False) """The message application. - .. note:: + !!! note This will only be provided for messages with rich-presence related chat embeds. """ @@ -556,9 +555,9 @@ class PartialMessage(snowflakes.Unique): referenced_message: undefined.UndefinedNoneOr[PartialMessage] = attrs.field(hash=False, eq=False, repr=False) """The message that was replied to. - If `type` is `MessageType.REPLY` and `hikari.undefined.UNDEFINED`, Discord's + If `type` is [`hikari.messages.MessageType.REPLY`][] and [`hikari.undefined.UNDEFINED`][], Discord's backend didn't attempt to fetch the message, so the status is unknown. If - `type` is `MessageType.REPLY` and `None`, the message was deleted. + `type` is [`hikari.messages.MessageType.REPLY`][] and [`None`][], the message was deleted. """ interaction: undefined.UndefinedNoneOr[MessageInteraction] = attrs.field(hash=False, eq=False, repr=False) @@ -567,7 +566,7 @@ class PartialMessage(snowflakes.Unique): application_id: undefined.UndefinedNoneOr[snowflakes.Snowflake] = attrs.field(hash=False, eq=False, repr=False) """ID of the application this message was sent by. - .. note:: + !!! note This will only be provided for interaction messages. """ @@ -582,7 +581,7 @@ def channel_mention_ids(self) -> undefined.UndefinedOr[typing.Sequence[snowflake If the message is not crossposted, this will always be empty. - .. warning:: + !!! warning If the contents have not mutated and this is a message update event, some fields that are not affected may be empty instead. @@ -597,7 +596,7 @@ def channel_mention_ids(self) -> undefined.UndefinedOr[typing.Sequence[snowflake def user_mentions_ids(self) -> undefined.UndefinedOr[typing.Sequence[snowflakes.Snowflake]]: """Ids of the users who were notified by their mention in the message. - .. warning:: + !!! warning If the contents have not mutated and this is a message update event, some fields that are not affected may be empty instead. @@ -613,13 +612,13 @@ def get_member_mentions(self) -> undefined.UndefinedOr[typing.Mapping[snowflakes If this message was sent in a DM, this will always be empty. - .. warning:: + !!! warning This will only return valid results on gateway events. For REST endpoints, this will potentially be empty. This is a limitation of Discord's API, as they do not consistently notify of the ID of the guild a message was sent in. - .. note:: + !!! note If you are using a stateless application such as a stateless bot or a REST-only client, this will always be empty. Furthermore, if you are running a stateful bot and have the GUILD_MEMBERS @@ -627,7 +626,8 @@ def get_member_mentions(self) -> undefined.UndefinedOr[typing.Mapping[snowflakes Members that are not cached will not appear in this mapping. This means that there is a very small chance that some users provided - in `notified_users` may not be present here. + in [`hikari.messages.PartialMessage.user_mentions`][] may not be + present here. """ if self.user_mentions is undefined.UNDEFINED: return undefined.UNDEFINED @@ -646,13 +646,13 @@ def get_role_mentions(self) -> undefined.UndefinedOr[typing.Mapping[snowflakes.S If this message was sent in a DM, this will always be empty. - .. warning:: + !!! warning This will only return valid results on gateway events. For REST endpoints, this will potentially be empty. This is a limitation of Discord's API, as they do not consistently notify of the ID of the guild a message was sent in. - .. note:: + !!! note If you are using a stateless application such as a stateless bot or a REST-only client, this will always be empty. Furthermore, if you are running a stateful bot and have the GUILD intent @@ -660,8 +660,8 @@ def get_role_mentions(self) -> undefined.UndefinedOr[typing.Mapping[snowflakes.S Roles that are not cached will not appear in this mapping. This means that there is a very small chance that some role IDs provided - in `notifies_role_ids` may not be present here. This is a limitation - of Discord, again. + in [`hikari.messages.PartialMessage.role_mention_ids`][] may not be + present here. This is a limitation of Discord, again. """ if self.role_mention_ids is undefined.UNDEFINED: return undefined.UNDEFINED @@ -677,10 +677,10 @@ def make_link(self, guild: typing.Optional[snowflakes.SnowflakeishOr[guilds.Part Other Parameters ---------------- guild : typing.Optional[hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild]] - Object or ID of the guild this message is in or `None` + Object or ID of the guild this message is in or [`None`][] to generate a DM message link. - This parameter is necessary since `PartialMessage.guild_id` + This parameter is necessary since [`hikari.messages.PartialMessage.guild_id`][] isn't returned by the REST API regardless of whether the message is in a DM or not. @@ -745,38 +745,38 @@ async def edit( ) -> Message: """Edit an existing message in a given channel. - .. note:: + !!! note Mentioning everyone, roles, or users in message edits currently will not send a push notification showing a new mention to people on Discord. It will still highlight in their chat as if they were mentioned, however. - .. warning:: + !!! warning If you specify a text `content`, `mentions_everyone`, `mentions_reply`, `user_mentions`, and `role_mentions` will default - to `False` as the message will be re-parsed for mentions. This will + to [`False`][] as the message will be re-parsed for mentions. This will also occur if only one of the four are specified This is a limitation of Discord's design. If in doubt, specify all four of them each time. - .. warning:: + !!! warning If the message was not sent by your user, the only parameter you may provide to this call is the `flags` parameter. Anything - else will result in a `hikari.errors.ForbiddenError` being raised. + else will result in a [`hikari.errors.ForbiddenError`][] being raised. Parameters ---------- content : hikari.undefined.UndefinedOr[typing.Any] If provided, the message content to update with. If - `hikari.undefined.UNDEFINED`, then the content will not - be changed. If `None`, then the content will be removed. + [`hikari.undefined.UNDEFINED`][], then the content will not + be changed. If [`None`][], then the content will be removed. - Any other value will be cast to a `str` before sending. + Any other value will be cast to a [`str`][] before sending. - If this is a `hikari.embeds.Embed` and neither the `embed` or + If this is a [`hikari.embeds.Embed`][] and neither the `embed` or `embeds` kwargs are provided or if this is a - `hikari.files.Resourceish` and neither the + [`hikari.files.Resourceish`][] and neither the `attachment` or `attachments` kwargs are provided, the values will be overwritten. This allows for simpler syntax when sending an embed or an attachment alone. @@ -785,41 +785,41 @@ async def edit( ---------------- attachment : hikari.undefined.UndefinedNoneOr[typing.Union[hikari.files.Resourceish, hikari.messages.Attachment]] If provided, the attachment to set on the message. If - `hikari.undefined.UNDEFINED`, the previous attachment, if - present, is not changed. If this is `None`, then the + [`hikari.undefined.UNDEFINED`][], the previous attachment, if + present, is not changed. If this is [`None`][], then the attachment is removed, if present. Otherwise, the new attachment that was provided will be attached. attachments : hikari.undefined.UndefinedNoneOr[typing.Sequence[typing.Union[hikari.files.Resourceish, hikari.messages.Attachment]]] If provided, the attachments to set on the message. If - `hikari.undefined.UNDEFINED`, the previous attachments, if - present, are not changed. If this is `None`, then the + [`hikari.undefined.UNDEFINED`][], the previous attachments, if + present, are not changed. If this is [`None`][], then the attachments is removed, if present. Otherwise, the new attachments that were provided will be attached. component : hikari.undefined.UndefinedNoneOr[hikari.api.special_endpoints.ComponentBuilder] If provided, builder object of the component to set for this message. This component will replace any previously set components and passing - `None` will remove all components. + [`None`][] will remove all components. components : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.api.special_endpoints.ComponentBuilder]] If provided, a sequence of the component builder objects set for this message. These components will replace any previously set - components and passing `None` or an empty sequence will + components and passing [`None`][] or an empty sequence will remove all components. embed : hikari.undefined.UndefinedNoneOr[hikari.embeds.Embed] If provided, the embed to set on the message. If - `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed. - If this is `None` then any present embeds are removed. + [`hikari.undefined.UNDEFINED`][], the previous embed(s) are not changed. + If this is [`None`][] then any present embeds are removed. Otherwise, the new embed that was provided will be used as the replacement. embeds : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.embeds.Embed]] If provided, the embeds to set on the message. If - `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed. - If this is `None` then any present embeds are removed. + [`hikari.undefined.UNDEFINED`][], the previous embed(s) are not changed. + If this is [`None`][] then any present embeds are removed. Otherwise, the new embeds that were provided will be used as the replacement. mentions_everyone : hikari.undefined.UndefinedOr[bool] Sanitation for `@everyone` mentions. If - `hikari.undefined.UNDEFINED`, then the previous setting is - not changed. If `True`, then `@everyone`/`@here` mentions + [`hikari.undefined.UNDEFINED`][], then the previous setting is + not changed. If [`True`][], then `@everyone`/`@here` mentions in the message content will show up as mentioning everyone that can view the chat. mentions_reply : hikari.undefined.UndefinedOr[bool] @@ -829,31 +829,31 @@ async def edit( This will not do anything if this is not a reply message. user_mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.users.PartialUser], bool]] Sanitation for user mentions. If - `hikari.undefined.UNDEFINED`, then the previous setting is - not changed. If `True`, all valid user mentions will behave - as mentions. If `False`, all valid user mentions will not + [`hikari.undefined.UNDEFINED`][], then the previous setting is + not changed. If [`True`][], all valid user mentions will behave + as mentions. If [`False`][], all valid user mentions will not behave as mentions. You may alternatively pass a collection of - `hikari.snowflakes.Snowflake` user IDs, or - `hikari.users.PartialUser`-derived objects. + [`hikari.snowflakes.Snowflake`][] user IDs, or + [`hikari.users.PartialUser`][]-derived objects. role_mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.guilds.PartialRole], bool]] Sanitation for role mentions. If - `hikari.undefined.UNDEFINED`, then the previous setting is - not changed. If `True`, all valid role mentions will behave - as mentions. If `False`, all valid role mentions will not + [`hikari.undefined.UNDEFINED`][], then the previous setting is + not changed. If [`True`][], all valid role mentions will behave + as mentions. If [`False`][], all valid role mentions will not behave as mentions. You may alternatively pass a collection of - `hikari.snowflakes.Snowflake` role IDs, or - `hikari.guilds.PartialRole`-derived objects. + [`hikari.snowflakes.Snowflake`][] role IDs, or + [`hikari.guilds.PartialRole`][]-derived objects. flags : hikari.undefined.UndefinedOr[hikari.messages.MessageFlag] Optional flags to set on the message. If - `hikari.undefined.UNDEFINED`, then nothing is changed. + [`hikari.undefined.UNDEFINED`][], then nothing is changed. Note that some flags may not be able to be set. Currently the only - flags that can be set are `NONE` and `SUPPRESS_EMBEDS`. If you - have `MANAGE_MESSAGES` permissions, you can use this call to + flags that can be set are [`hikari.messages.MessageFlag.NONE`][] and [`hikari.messages.MessageFlag.SUPPRESS_EMBEDS`][]. If you + have [`hikari.permissions.Permissions.MANAGE_MESSAGES`][] permissions, you can use this call to suppress embeds on another user's message. Returns @@ -932,15 +932,15 @@ async def respond( ---------- content : hikari.undefined.UndefinedOr[typing.Any] If provided, the message contents. If - `hikari.undefined.UNDEFINED`, then nothing will be sent + [`hikari.undefined.UNDEFINED`][], then nothing will be sent in the content. Any other value here will be cast to a - `str`. + [`str`][]. - If this is a `hikari.embeds.Embed` and no `embed` nor `embeds` kwarg + 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 + 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. @@ -953,26 +953,26 @@ async def respond( Attachments can be passed as many different things, to aid in convenience. - - If a `pathlib.PurePath` or `str` to a valid URL, the + - 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. + [`hikari.files.WebResource`][] such as + [`hikari.files.URL`][], + [`hikari.messages.Attachment`][], + [`hikari.emojis.Emoji`][], + [`hikari.embeds.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` + - 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 + - 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 + 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]], @@ -998,12 +998,11 @@ async def respond( tts : hikari.undefined.UndefinedOr[bool] If provided, whether the message will be TTS (Text To Speech). reply : typing.Union[hikari.undefined.UndefinedType, hikari.snowflakes.SnowflakeishOr[hikari.messages.PartialMessage], bool] - If provided and `True`, reply to this message. - If provided and not `bool`, the message to reply to. + If provided and [`True`][], reply to this message. + If provided and not [`bool`][], the message to reply to. reply_must_exist : hikari.undefined.UndefinedOr[bool] If provided, whether to error if the message being replied to does not exist instead of sending as a normal (non-reply) message. - Defaults to `True`. This will not do anything if not being used with `reply`. mentions_everyone : hikari.undefined.UndefinedOr[bool] @@ -1015,24 +1014,24 @@ async def respond( 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 mentions will be parsed. - If provided, and `False`, no mentions will be parsed. + If provided, and [`True`][], all mentions will be parsed. + If provided, and [`False`][], no mentions will be parsed. Alternatively this may be a collection of - `hikari.snowflakes.Snowflake`, or `hikari.users.PartialUser` + [`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 mentions will be parsed. - If provided, and `False`, no mentions will be parsed. + If provided, and [`True`][], all mentions will be parsed. + If provided, and [`False`][], no mentions will be parsed. Alternatively this may be a collection of - `hikari.snowflakes.Snowflake`, or - `hikari.guilds.PartialRole` derivatives to enforce mentioning + [`hikari.snowflakes.Snowflake`][], or + [`hikari.guilds.PartialRole`][] derivatives to enforce mentioning specific roles. flags : hikari.undefined.UndefinedOr[hikari.messages.MessageFlag] If provided, optional flags to set on the message. If - `hikari.undefined.UNDEFINED`, then nothing is changed. + [`hikari.undefined.UNDEFINED`][], then nothing is changed. Note that some flags may not be able to be set. Currently the only - flags that can be set are `NONE` and `SUPPRESS_EMBEDS`. + flags that can be set are [`hikari.messages.MessageFlag.NONE`][] and [`hikari.messages.MessageFlag.SUPPRESS_EMBEDS`][]. Returns ------- @@ -1120,7 +1119,7 @@ async def add_reaction( emoji : typing.Union[str, hikari.emojis.Emoji] Object or name of the emoji to react with. - Note that if the emoji is an `hikari.emojis.CustomEmoji` + Note that if the emoji is an [`hikari.emojis.CustomEmoji`][] and is not from a guild the bot user is in, then this will fail. Other Parameters @@ -1135,8 +1134,7 @@ async def add_reaction( Examples -------- - .. code-block:: python - + ```py # Using a unicode emoji. await message.add_reaction("👌") @@ -1148,6 +1146,7 @@ async def add_reaction( # Using an Emoji-derived object. await message.add_reaction(some_emoji_object) + ``` Raises ------ @@ -1155,8 +1154,8 @@ async def add_reaction( If the emoji is invalid, unknown, or formatted incorrectly. hikari.errors.ForbiddenError If this is the first reaction using this specific emoji on this - message and you lack the `ADD_REACTIONS` permission. If you lack - `READ_MESSAGE_HISTORY`, this may also raise this error. + message and you lack the [`hikari.permissions.Permissions.ADD_REACTIONS`][] permission. If you lack + [`hikari.permissions.Permissions.READ_MESSAGE_HISTORY`][], this may also raise this error. hikari.errors.NotFoundError If the channel or message is not found, or if the emoji is not found. @@ -1210,8 +1209,7 @@ async def remove_reaction( Examples -------- - .. code-block:: python - + ```py # Using a unicode emoji and removing the bot's reaction from this # reaction. await message.remove_reaction("\N{OK HAND SIGN}") @@ -1230,6 +1228,7 @@ async def remove_reaction( # Using an Emoji object and removing a specific user from this # reaction. await message.remove_reaction(some_emoji_object, user=some_user) + ``` Raises ------ @@ -1239,9 +1238,9 @@ async def remove_reaction( due to it being outside of the range of a 64 bit integer. hikari.errors.ForbiddenError If this is the first reaction using this specific emoji on this - message and you lack the `ADD_REACTIONS` permission. If you lack - `READ_MESSAGE_HISTORY`, this may also raise this error. If you - remove the reaction of another user without `MANAGE_MESSAGES`, this + message and you lack the [`hikari.permissions.Permissions.ADD_REACTIONS`][] permission. If you lack + [`hikari.permissions.Permissions.READ_MESSAGE_HISTORY`][], this may also raise this error. If you + remove the reaction of another user without [`hikari.permissions.Permissions.MANAGE_MESSAGES`][], this will be raised. hikari.errors.NotFoundError If the channel or message is not found, or if the emoji is not @@ -1286,8 +1285,7 @@ async def remove_all_reactions( Examples -------- - .. code-block:: python - + ```py # Using a unicode emoji and removing all 👌 reacts from the message. # reaction. await message.remove_all_reactions("\N{OK HAND SIGN}") @@ -1297,11 +1295,12 @@ async def remove_all_reactions( # Removing all reactions entirely. await message.remove_all_reactions() + ``` Raises ------ hikari.errors.ForbiddenError - If you are missing the `MANAGE_MESSAGES` permission, or the + If you are missing the [`hikari.permissions.Permissions.MANAGE_MESSAGES`][] permission, or the permission to view the channel hikari.errors.NotFoundError If the channel or message is not found, or if the emoji is not @@ -1338,7 +1337,7 @@ class Message(PartialMessage): edited_timestamp: typing.Optional[datetime.datetime] = attrs.field(hash=False, eq=False, repr=False) """The timestamp that the message was last edited at. - Will be `None` if it wasn't ever edited. + Will be [`None`][] if it wasn't ever edited. """ is_tts: bool = attrs.field(hash=False, eq=False, repr=False) @@ -1365,7 +1364,7 @@ class Message(PartialMessage): activity: typing.Optional[MessageActivity] = attrs.field(hash=False, eq=False, repr=False) """The message activity. - .. note:: + !!! note This will only be provided for messages with rich-presence related chat embeds. """ @@ -1373,7 +1372,7 @@ class Message(PartialMessage): application: typing.Optional[MessageApplication] = attrs.field(hash=False, eq=False, repr=False) """The message application. - .. note:: + !!! note This will only be provided for messages with rich-presence related chat embeds. """ @@ -1393,7 +1392,7 @@ class Message(PartialMessage): referenced_message: typing.Optional[PartialMessage] = attrs.field(hash=False, eq=False, repr=False) """The message that was replied to. - If `type` is `MessageType.REPLY` and `None`, the message was deleted. + If `type` is [`hikari.messages.MessageType.REPLY`][] and [`None`][], the message was deleted. """ interaction: typing.Optional[MessageInteraction] = attrs.field(hash=False, eq=False, repr=False) @@ -1402,7 +1401,7 @@ class Message(PartialMessage): application_id: typing.Optional[snowflakes.Snowflake] = attrs.field(hash=False, eq=False, repr=False) """ID of the application this message was sent by. - .. note:: + !!! note This will only be provided for interaction messages. """ diff --git a/hikari/permissions.py b/hikari/permissions.py index f709c49be8..505c48c9ff 100644 --- a/hikari/permissions.py +++ b/hikari/permissions.py @@ -35,7 +35,7 @@ class Permissions(enums.Flag): """Represents the permissions available in a given channel or guild. - This enum is an `enum.IntFlag`, which means that it is stored as a bit field + This enum is an [`enum.IntFlag`][], which means that it is stored as a bit field where each bit represents a permission. You can use bitwise operators to efficiently manipulate and compare permissions. @@ -43,8 +43,7 @@ class Permissions(enums.Flag): -------- You can create an enum which combines multiple permissions using the bitwise OR operator (`|`): - .. code-block:: python - + ```py my_perms = Permissions.MANAGE_CHANNELS | Permissions.MANAGE_GUILD required_perms = ( @@ -53,37 +52,37 @@ class Permissions(enums.Flag): | Permissions.BAN_MEMBERS | Permissions.MANAGE_GUILD ) + ``` To find the intersection of two sets of permissions, use the bitwise AND operator (`&`) between them. By then applying the `==` operator, you can check if all permissions from one set are present in another set. This is useful, for instance, for checking if a user has all the required permissions - .. code-block:: python - + ```py if (my_perms & required_perms) == required_perms: print("I have all of the required permissions!") else: print("I am missing at least one required permission!") + ``` To determine which permissions from one set are missing from another, you can use the bitwise equivalent of the set difference operation, as shown below. This can be used, for instance, to find which of a user's permissions are missing from the required permissions. - .. code-block:: python - - missing_perms = ~my_perms & required_perms - if (missing_perms): - print(f"I'm missing these permissions: {missing_perms}") + ```py + missing_perms = ~my_perms & required_perms + if (missing_perms): + print(f"I'm missing these permissions: {missing_perms}") + ``` Lastly, if you need all the permissions from a set except for a few, you can use the bitwise NOT operator (`~`). - .. code-block:: python - + ```py # All permissions except ADMINISTRATOR. my_perms = ~Permissions.ADMINISTRATOR - + ``` """ NONE = 0 @@ -95,7 +94,7 @@ class Permissions(enums.Flag): KICK_MEMBERS = 1 << 1 """Allows kicking members. - .. note:: + !!! note In guilds with server-wide 2FA enabled this permission can only be used by users who have two-factor authentication enabled on their account (or their owner's account in the case of bot users) and the guild owner. @@ -104,7 +103,7 @@ class Permissions(enums.Flag): BAN_MEMBERS = 1 << 2 """Allows banning members. - .. note:: + !!! note In guilds with server-wide 2FA enabled this permission can only be used by users who have two-factor authentication enabled on their account (or their owner's account in the case of bot users) and the guild owner. @@ -113,7 +112,7 @@ class Permissions(enums.Flag): ADMINISTRATOR = 1 << 3 """Allows all permissions and bypasses channel permission overwrites. - .. note:: + !!! note In guilds with server-wide 2FA enabled this permission can only be used by users who have two-factor authentication enabled on their account (or their owner's account in the case of bot users) and the guild owner. @@ -122,7 +121,7 @@ class Permissions(enums.Flag): MANAGE_CHANNELS = 1 << 4 """Allows management and editing of channels. - .. note:: + !!! note In guilds with server-wide 2FA enabled this permission can only be used by users who have two-factor authentication enabled on their account (or their owner's account in the case of bot users) and the guild owner. @@ -131,7 +130,7 @@ class Permissions(enums.Flag): MANAGE_GUILD = 1 << 5 """Allows management and editing of the guild. - .. note:: + !!! note In guilds with server-wide 2FA enabled this permission can only be used by users who have two-factor authentication enabled on their account (or their owner's account in the case of bot users) and the guild owner. @@ -156,12 +155,12 @@ class Permissions(enums.Flag): """Allows for sending messages in a channel.""" SEND_TTS_MESSAGES = 1 << 12 - """Allows for sending of `/tts` messages.""" + """Allows for sending of [/tts][] messages.""" MANAGE_MESSAGES = 1 << 13 """Allows for deletion of other users messages. - .. note:: + !!! note In guilds with server-wide 2FA enabled this permission can only be used by users who have two-factor authentication enabled on their account (or their owner's account in the case of bot users) and the guild owner. @@ -212,7 +211,7 @@ class Permissions(enums.Flag): MANAGE_ROLES = 1 << 28 """Allows management and editing of roles. - .. note:: + !!! note In guilds with server-wide 2FA enabled this permission can only be used by users who have two-factor authentication enabled on their account (or their owner's account in the case of bot users) and the guild owner. @@ -221,7 +220,7 @@ class Permissions(enums.Flag): MANAGE_WEBHOOKS = 1 << 29 """Allows management and editing of webhooks. - .. note:: + !!! note In guilds with server-wide 2FA enabled this permission can only be used by users who have two-factor authentication enabled on their account (or their owner's account in the case of bot users) and the guild owner. @@ -230,7 +229,7 @@ class Permissions(enums.Flag): MANAGE_GUILD_EXPRESSIONS = 1 << 30 """Allows management and editing emojis, stickers and soundboard sounds. - .. note:: + !!! note In guilds with server-wide 2FA enabled this permission can only be used by users who have two-factor authentication enabled on their account (or their owner's account in the case of bot users) and the guild owner. @@ -242,7 +241,7 @@ class Permissions(enums.Flag): REQUEST_TO_SPEAK = 1 << 32 """Allows for requesting to speak in stage channels. - .. warning:: + !!! warning This permissions is currently defined as being "under active development" by Discord meaning that "it may be changed or removed" without warning. @@ -254,7 +253,7 @@ class Permissions(enums.Flag): MANAGE_THREADS = 1 << 34 """Allows for deleting and archiving threads, and viewing all private threads. - .. note:: + !!! note In guilds with server-wide 2FA enabled this permission can only be used by users who have two-factor authentication enabled on their account (or their owner's account in the case of bot users) and the guild owner. @@ -273,7 +272,10 @@ class Permissions(enums.Flag): """Allows for sending messages in threads.""" START_EMBEDDED_ACTIVITIES = 1 << 39 - """Allows for launching activities (applications with the `EMBEDDED` flag) in a voice channel.""" + """Allows for launching activities in a voice channel. + + Activities are applications that have the [`hikari.applications.ApplicationFlags.EMBEDDED`][] flag. + """ MODERATE_MEMBERS = 1 << 40 """Allows for timing out members.""" @@ -304,7 +306,7 @@ class Permissions(enums.Flag): @classmethod def all_permissions(cls) -> Permissions: - """Get an instance of `Permissions` with all the known permissions. + """Get an instance of [`hikari.permissions.Permissions`][] with all the known permissions. Returns ------- diff --git a/hikari/presences.py b/hikari/presences.py index 6d879bfcf6..a93ac9ca7d 100644 --- a/hikari/presences.py +++ b/hikari/presences.py @@ -68,7 +68,7 @@ class ActivityType(int, enums.Enum): STREAMING = 1 """Shows up as `Streaming` and links to a Twitch or YouTube stream/video. - .. warning:: + !!! warning You **MUST** provide a valid Twitch or YouTube stream URL to the activity you create in order for this to be valid. If you fail to do this, then the activity **WILL NOT** update. @@ -83,7 +83,7 @@ class ActivityType(int, enums.Enum): CUSTOM = 4 """Shows up as ` `. - .. warning:: + !!! warning As of the time of writing, emoji cannot be used by bot accounts. """ @@ -161,8 +161,8 @@ def _make_asset_url(self, asset: typing.Optional[str], ext: str, size: int) -> t def large_image_url(self) -> typing.Optional[files.URL]: """Large image asset URL. - .. note:: - This will be `None` if no large image asset exists or if the + !!! note + This will be [`None`][] if no large image asset exists or if the asset's dynamic URL (indicated by a `{name}:` prefix) is not known. """ try: @@ -174,23 +174,23 @@ def large_image_url(self) -> typing.Optional[files.URL]: def make_large_image_url(self, *, ext: str = "png", size: int = 4096) -> typing.Optional[files.URL]: """Generate the large image asset URL for this application. - .. note:: + !!! note `ext` and `size` are ignored for images hosted outside of Discord or on Discord's media proxy. Parameters ---------- ext : str - The extension to use for this URL, defaults to `png`. + The extension to use for this URL. Supports `png`, `jpeg`, `jpg` and `webp`. size : int - The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- typing.Optional[hikari.files.URL] - The URL, or `None` if no icon exists. + The URL, or [`None`][] if no icon exists. Raises ------ @@ -198,7 +198,7 @@ def make_large_image_url(self, *, ext: str = "png", size: int = 4096) -> typing. If the size is not an integer power of 2 between 16 and 4096 (inclusive). RuntimeError - If `ActivityAssets.large_image` points towards an unknown asset type. + If [`hikari.presences.ActivityAssets.large_image`][] points towards an unknown asset type. """ return self._make_asset_url(self.large_image, ext, size) @@ -206,8 +206,8 @@ def make_large_image_url(self, *, ext: str = "png", size: int = 4096) -> typing. def small_image_url(self) -> typing.Optional[files.URL]: """Small image asset URL. - .. note:: - This will be `None` if no large image asset exists or if the + !!! note + This will be [`None`][] if no large image asset exists or if the asset's dynamic URL (indicated by a `{name}:` prefix) is not known. """ try: @@ -222,16 +222,16 @@ def make_small_image_url(self, *, ext: str = "png", size: int = 4096) -> typing. Parameters ---------- ext : str - The extension to use for this URL, defaults to `png`. + The extension to use for this URL. Supports `png`, `jpeg`, `jpg` and `webp`. size : int - The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- typing.Optional[hikari.files.URL] - The URL, or `None` if no icon exists. + The URL, or [`None`][] if no icon exists. Raises ------ @@ -239,7 +239,7 @@ def make_small_image_url(self, *, ext: str = "png", size: int = 4096) -> typing. If the size is not an integer power of 2 between 16 and 4096 (inclusive). RuntimeError - If `ActivityAssets.small_image` points towards an unknown asset type. + If [`hikari.presences.ActivityAssets.small_image`][] points towards an unknown asset type. """ return self._make_asset_url(self.small_image, ext, size) @@ -313,7 +313,7 @@ class Activity: url: typing.Optional[str] = attrs.field(default=None, repr=False) """The activity URL, if set. - Only valid for `STREAMING` activities. + Only valid for [`hikari.presences.ActivityType.STREAMING`][] activities. """ type: typing.Union[ActivityType, int] = attrs.field(converter=ActivityType, default=ActivityType.PLAYING) diff --git a/hikari/scheduled_events.py b/hikari/scheduled_events.py index 170861432b..187da9fd85 100644 --- a/hikari/scheduled_events.py +++ b/hikari/scheduled_events.py @@ -89,7 +89,7 @@ class ScheduledEventStatus(int, enums.Enum): """Indicates an event has been canceled.""" CANCELLED = CANCELED - """Alias of `ScheduledEventStatus.CANCELED`.""" + """Alias of [`hikari.scheduled_events.ScheduledEventStatus.CANCELED`][].""" @attrs_extensions.with_copy @@ -144,7 +144,7 @@ class ScheduledEvent(snowflakes.Unique): user_count: typing.Optional[int] = attrs.field(hash=False, repr=False) """The number of users that have subscribed to the event. - This will be `None` on gateway events when creating and + This will be [`None`][] on gateway events when creating and editing a scheduled event. """ @@ -162,16 +162,16 @@ def make_image_url(self, *, ext: str = "png", size: int = 4096) -> typing.Option Parameters ---------- ext : str - The extension to use for this URL, defaults to `png`. - Supports `png`, `jpeg`, `jpg` and `webp`. + The extension to use for this URL. + supports `png`, `jpeg`, `jpg` and `webp`. size : int - The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- typing.Optional[hikari.files.URL] - The URL, or `None` if no cover image is set. + The URL, or [`None`][] if no cover image is set. Raises ------ @@ -194,7 +194,7 @@ class ScheduledExternalEvent(ScheduledEvent): location: str = attrs.field(hash=False, repr=False) """The location of the scheduled event. - .. note:: + !!! note There is no strict format for this field, and it will likely be a user friendly string. """ diff --git a/hikari/sessions.py b/hikari/sessions.py index e0ea1693bd..d42c1648cd 100644 --- a/hikari/sessions.py +++ b/hikari/sessions.py @@ -49,9 +49,9 @@ class SessionStartLimit: """The remaining number of session starts this bot has.""" reset_after: datetime.timedelta = attrs.field(repr=True) - """When `SessionStartLimit.remaining` will reset for the current bot. + """When [`hikari.sessions.SessionStartLimit.remaining`][] will reset for the current bot. - After it resets it will be set to `SessionStartLimit.total`. + After it resets it will be set to [`hikari.sessions.SessionStartLimit.total`][]. """ # This is not documented at the time of writing, but is a confirmed API diff --git a/hikari/snowflakes.py b/hikari/snowflakes.py index 50155392a5..9cf4d2179d 100644 --- a/hikari/snowflakes.py +++ b/hikari/snowflakes.py @@ -52,7 +52,7 @@ class Snowflake(int): """A concrete representation of a unique ID for an entity on Discord. - This object can be treated as a regular `int` for most purposes. + This object can be treated as a regular [`int`][] for most purposes. """ __slots__: typing.Sequence[str] = () @@ -154,31 +154,31 @@ def calculate_shard_id( Snowflakeish = typing.Union[Snowflake, int] -"""Type hint for a value that resembles a `Snowflake` object functionally. +"""Type hint for a value that resembles a [`hikari.snowflakes.Snowflake`][] object functionally. -This is a value that is `Snowflake`-ish. +This is a value that is [`hikari.snowflakes.Snowflake`][]-ish. -A value is `Snowflake`-ish if casting it to an `int` allows it to be cast to -a `Snowflake`. +A value is [`hikari.snowflakes.Snowflake`][]-ish if casting it to an [`int`][] allows it to be cast to +a [`hikari.snowflakes.Snowflake`][]. The valid types for this type hint are: -- `int` -- `Snowflake` +- [`int`][] +- [`hikari.snowflakes.Snowflake`][] """ SearchableSnowflakeish = typing.Union[Snowflakeish, "datetime.datetime"] """Type hint for a snowflakeish that can be searched for in history. -This is just a `Snowflakeish` that can alternatively be some form of -`datetime.datetime` instance. +This is just a [`hikari.snowflakes.Snowflakeish`][] that can alternatively be some form of +[`datetime.datetime`][] instance. The valid types for this type hint are: -- `str` containing digits. -- `int` -- `Snowflake` -- `datetime.datetime` +- [`str`][] containing digits. +- [`int`][] +- [`hikari.snowflakes.Snowflake`][] +- [`datetime.datetime`][] """ T = typing.TypeVar("T", covariant=True, bound=Unique) @@ -186,10 +186,10 @@ def calculate_shard_id( SnowflakeishOr = typing.Union[T, Snowflakeish] """Type hint representing a unique object entity. -This is a value that is `Snowflake`-ish or a specific type covariant. +This is a value that is [`hikari.snowflakes.Snowflake`][]-ish or a specific type covariant. If you see `SnowflakeishOr[Foo]` anywhere as a type hint, it means the value -may be a `Foo` instance, a `Snowflake`, a `int` or a `str` +may be a `Foo` instance, a [`hikari.snowflakes.Snowflake`][], an [`int`][] or a [`str`][] with numeric digits only. Essentially this represents any concrete object, or ID of that object. It is @@ -199,15 +199,15 @@ def calculate_shard_id( The valid types for this type hint are: -- `int` -- `Snowflake` +- [`int`][] +- [`hikari.snowflakes.Snowflake`][] """ SearchableSnowflakeishOr = typing.Union[T, SearchableSnowflakeish] """Type hint for a unique object entity that can be searched for. -This is a variant of `SnowflakeishOr` that also allows an alternative value -of a `datetime.datetime` to be specified. +This is a variant of [`hikari.snowflakes.SnowflakeishOr`][] that also allows an alternative value +of a [`datetime.datetime`][] to be specified. Essentially this represents any concrete object, or ID of that object. It is used across Hikari's API to allow use of functions when information is only @@ -216,9 +216,9 @@ def calculate_shard_id( The valid types for this type hint are: -- `int` -- `Snowflake` -- `datetime.datetime` +- [`int`][] +- [`hikari.snowflakes.Snowflake`][] +- [`datetime.datetime`][] """ SnowflakeishIterable = typing.Iterable[SnowflakeishOr[T]] diff --git a/hikari/stickers.py b/hikari/stickers.py index bd619bf5d2..38e108b9d4 100644 --- a/hikari/stickers.py +++ b/hikari/stickers.py @@ -121,11 +121,11 @@ def make_banner_url(self, *, ext: str = "png", size: int = 4096) -> typing.Optio Parameters ---------- ext : str - The extension to use for this URL, defaults to `png`. + The extension to use for this URL. Supports `png`, `jpeg`, `jpg` and `webp`. size : int - The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Returns ------- @@ -163,8 +163,9 @@ class PartialSticker(snowflakes.Unique): def image_url(self) -> files.URL: """URL for the image. - The extension will be based on `format_type`. If `format_type` is `StickerFormatType.LOTTIE`, - then the extension will be `.json`, if it's `StickerFormatType.GIF` it will be `.gif`. Otherwise, it will be `.png`. + The extension will be based on `format_type`. If `format_type` is [`hikari.stickers.StickerFormatType.LOTTIE`][], + then the extension will be `.json`, if it's [`hikari.stickers.StickerFormatType.GIF`][] it will be `.gif`. + Otherwise, it will be `.png`. """ ext = _STICKER_EXTENSIONS.get(self.format_type, "png") @@ -215,5 +216,5 @@ class GuildSticker(PartialSticker): user: typing.Optional[users.User] = attrs.field(eq=False, hash=False, repr=False) """The user that uploaded this sticker. - This will only available if you have the `MANAGE_EMOJIS_AND_STICKERS` permission. + This will only be available if you have the [`hikari.permissions.Permissions.MANAGE_GUILD_EXPRESSIONS`][] permission. """ diff --git a/hikari/templates.py b/hikari/templates.py index 9d4cd4d05f..ccb2b898bf 100644 --- a/hikari/templates.py +++ b/hikari/templates.py @@ -48,7 +48,7 @@ @attrs_extensions.with_copy @attrs.define(hash=True, kw_only=True, weakref_slot=False) class TemplateRole(guilds.PartialRole): - """The partial role object attached to `Template`.""" + """The partial role object attached to [`hikari.templates.Template`][].""" permissions: permissions_.Permissions = attrs.field(eq=False, hash=False, repr=False) """The guild wide permissions this role gives to the members it's attached to. @@ -65,7 +65,7 @@ class TemplateRole(guilds.PartialRole): is_hoisted: bool = attrs.field(eq=False, hash=False, repr=True) """Whether this role is hoisting the members it's attached to in the member list. - members will be hoisted under their highest role where this is set to `True`. + members will be hoisted under their highest role where this is set to [`True`][]. """ is_mentionable: bool = attrs.field(eq=False, hash=False, repr=False) @@ -75,7 +75,7 @@ class TemplateRole(guilds.PartialRole): @attrs_extensions.with_copy @attrs.define(hash=True, kw_only=True, weakref_slot=False) class TemplateGuild(guilds.PartialGuild): - """The partial guild object attached to `Template`.""" + """The partial guild object attached to [`hikari.templates.Template`][].""" description: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) """The guild's description, if set.""" @@ -96,7 +96,7 @@ class TemplateGuild(guilds.PartialGuild): preferred_locale: str = attrs.field(eq=False, hash=False, repr=False) """The preferred locale to use for this guild. - This can only be change if `GuildFeature.COMMUNITY` is in `Guild.features` + This can only be change if [`hikari.guilds.GuildFeature.COMMUNITY`][] is in [`hikari.guilds.Guild.features`][] for this guild and will otherwise default to `en-US`. """ @@ -104,14 +104,14 @@ class TemplateGuild(guilds.PartialGuild): """Timeout for activity before a member is classed as AFK. How long a voice user has to be AFK for before they are classed as being - AFK and are moved to the AFK channel (`Guild.afk_channel_id`). + AFK and are moved to the AFK channel ([`hikari.guilds.Guild.afk_channel_id`][]). """ roles: typing.Mapping[snowflakes.Snowflake, TemplateRole] = attrs.field(eq=False, hash=False, repr=False) """The roles in the guild. - .. note:: - `hikari.guilds.Role.id` will be a unique placeholder on all the role + !!! note + [`hikari.guilds.Role.id`][] will be a unique placeholder on all the role objects found attached this template guild. """ @@ -120,19 +120,19 @@ class TemplateGuild(guilds.PartialGuild): ) """The channels for the guild. - .. note:: - `hikari.channels.GuildChannel.id` will be a unique placeholder on all + !!! note + [`hikari.channels.GuildChannel.id`][] will be a unique placeholder on all the channel objects found attached this template guild. """ afk_channel_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) """The ID for the channel that AFK voice users get sent to. - If `None`, then no AFK channel is set up for this guild. + If [`None`][], then no AFK channel is set up for this guild. """ system_channel_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=False) - """The ID of the system channel or `None` if it is not enabled. + """The ID of the system channel or [`None`][] if it is not enabled. Welcome messages and Nitro boost messages may be sent to this channel. """ @@ -228,7 +228,7 @@ async def edit( hikari.errors.ForbiddenError If you are not part of the guild. hikari.errors.NotFoundError - If the guild is not found or you are missing the `MANAGE_GUILD` permission. + If the guild is not found or you are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.RateLimitTooLongError @@ -246,7 +246,7 @@ async def delete(self) -> None: hikari.errors.ForbiddenError If you are not part of the guild. hikari.errors.NotFoundError - If the guild is not found or you are missing the `MANAGE_GUILD` permission. + If the guild is not found or you are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.RateLimitTooLongError @@ -267,7 +267,7 @@ async def sync(self) -> Template: Raises ------ hikari.errors.ForbiddenError - If you are not part of the guild or are missing the `MANAGE_GUILD` permission. + If you are not part of the guild or are missing the [`hikari.permissions.Permissions.MANAGE_GUILD`][] permission. hikari.errors.NotFoundError If the guild or template is not found. hikari.errors.UnauthorizedError @@ -282,7 +282,7 @@ async def sync(self) -> Template: async def create_guild(self, name: str, *, icon: undefined.UndefinedOr[str]) -> guilds.RESTGuild: """Make a guild from a template. - .. note:: + !!! note This endpoint can only be used by bots in less than 10 guilds. Parameters diff --git a/hikari/traits.py b/hikari/traits.py index 33b908a878..11efa31ec0 100644 --- a/hikari/traits.py +++ b/hikari/traits.py @@ -125,8 +125,8 @@ class ExecutorAware(fast_protocol.FastProtocolChecking, typing.Protocol): """Structural supertype for an executor-aware object. These components will contain an `executor` attribute that may return - a `concurrent.futures.Executor` or `None` if the - default `asyncio` thread pool for the event loop is used. + a [`concurrent.futures.Executor`][] or [`None`][] if the + default [`asyncio`][] thread pool for the event loop is used. """ __slots__: typing.Sequence[str] = () @@ -136,7 +136,7 @@ class ExecutorAware(fast_protocol.FastProtocolChecking, typing.Protocol): def executor(self) -> typing.Optional[futures.Executor]: """Executor to use for blocking operations. - This may return `None` if the default `asyncio` thread pool + This may return [`None`][] if the default [`asyncio`][] thread pool should be used instead. """ raise NotImplementedError @@ -263,14 +263,14 @@ def get_me(self) -> typing.Optional[users_.OwnUser]: """Return the bot user, if known. This should be available as soon as the bot has fired the - `hikari.events.lifetime_events.StartingEvent`. + [`hikari.events.lifetime_events.StartingEvent`][]. - Until then, this may or may not be `None`. + Until then, this may or may not be [`None`][]. Returns ------- typing.Optional[hikari.users.OwnUser] - The bot user, if known, otherwise `None`. + The bot user, if known, otherwise [`None`][]. """ raise NotImplementedError @@ -290,15 +290,15 @@ async def update_presence( retained. This means you do not have to track the global presence in your code. - .. note:: + !!! note This will only send the update payloads to shards that are alive. Any shards that are not alive will cache the new presence for when they do start. - .. note:: + !!! note If you want to set presences per shard, access the shard you wish - to update (e.g. by using `GatewayBot.shards`), and call - `hikari.api.shard.GatewayShard.update_presence` on that shard. + to update (e.g. by using [`hikari.GatewayBot.shards`][]), and call + [`hikari.api.shard.GatewayShard.update_presence`][] on that shard. This method is simply a facade to make performing this in bulk simpler. @@ -308,8 +308,7 @@ async def update_presence( The datetime that the user started being idle. If undefined, this will not be changed. afk : hikari.undefined.UndefinedOr[bool] - If `True`, the user is marked as AFK. If `False`, - the user is marked as being active. If undefined, this will not be + Whether to be marked as AFK. If undefined, this will not be changed. activity : hikari.undefined.UndefinedNoneOr[hikari.presences.Activity] The activity to appear to be playing. If undefined, this will not be @@ -335,15 +334,15 @@ async def update_voice_state( guild : hikari.snowflakes.SnowflakeishOr[hikari.guilds.PartialGuild] The guild or guild ID to update the voice state for. channel : typing.Optional[hikari.snowflakes.SnowflakeishOr[hikari.channels.GuildVoiceChannel]] - The channel or channel ID to update the voice state for. If `None` + The channel or channel ID to update the voice state for. If [`None`][] then the bot will leave the voice channel that it is in for the given guild. self_mute : bool - If specified and `True`, the bot will mute itself in that - voice channel. If `False`, then it will unmute itself. + If specified and [`True`][], the bot will mute itself in that + voice channel. If [`False`][], then it will unmute itself. self_deaf : bool - If specified and `True`, the bot will deafen itself in that - voice channel. If `False`, then it will undeafen itself. + If specified and [`True`][], the bot will deafen itself in that + voice channel. If [`False`][], then it will undeafen itself. Raises ------ @@ -365,7 +364,7 @@ async def request_guild_members( ) -> None: """Request for a guild chunk. - .. note:: + !!! note To request the full list of members, set `query` to `""` (empty string) and `limit` to `0`. @@ -390,11 +389,11 @@ async def request_guild_members( Raises ------ ValueError - When trying to specify `users` with `query`/`limit`, if `limit` is not between + If trying to specify `users` with `query`/`limit`, if `limit` is not between 0 and 100, both inclusive or if `users` length is over 100. hikari.errors.MissingIntentError - When trying to request presences without the `GUILD_MEMBERS` or when trying to - request the full list of members without `GUILD_PRESENCES`. + When trying to request presences without the [`hikari.intents.Intents.GUILD_MEMBERS`][] or when trying to + request the full list of members without [`hikari.intents.Intents.GUILD_PRESENCES`][]. RuntimeError If the guild passed isn't covered by any of the shards in this sharded client. @@ -442,8 +441,8 @@ def is_alive(self) -> bool: """Whether the application is running or not. This is useful as some functions might raise - `hikari.errors.ComponentStateConflictError` if this is - `False`. + [`hikari.errors.ComponentStateConflictError`][] if this is + [`False`][]. """ raise NotImplementedError diff --git a/hikari/undefined.py b/hikari/undefined.py index 9bd4a28956..8284d9ab32 100644 --- a/hikari/undefined.py +++ b/hikari/undefined.py @@ -41,7 +41,7 @@ class UndefinedType: - """The type of the `UNDEFINED` singleton sentinel value.""" + """The type of the [`hikari.undefined.UNDEFINED`][] singleton sentinel value.""" __slots__: typing.Sequence[str] = () @@ -59,7 +59,7 @@ def __deepcopy__(self, memo: typing.MutableMapping[int, typing.Any]) -> Self: return self def __getstate__(self) -> typing.Any: - # Returning False tells pickle to not call `__setstate__` on unpickling. + # Returning False tells pickle to not call [`__setstate__`][] on unpickling. return False def __repr__(self) -> str: @@ -88,38 +88,39 @@ def __new__(cls: UndefinedType) -> typing.NoReturn: # pragma: nocover UndefinedOr = typing.Union[T, UndefinedType] """Type hint to mark a type as being semantically optional. -**NOTE THAT THIS IS NOT THE SAME AS `typing.Optional` BY DEFINITION**. +!!! warning "**THIS IS NOT THE SAME AS [`typing.Optional`][] BY DEFINITION!**" + If you see a type with this marker, it may be [`hikari.undefined.UNDEFINED`][] or + the value it wraps. For example, `UndefinedOr[float]` would mean the value could + be a [`float`][], or the literal [`hikari.undefined.UNDEFINED`][] value. -If you see a type with this marker, it may be `UNDEFINED` or the value it wraps. -For example, `UndefinedOr[float]` would mean the value could be a -`float`, or the literal `UNDEFINED` value. + On the other hand, `typing.Optional[float]` would mean the value could be + a [`float`][], or the literal [`None`][] value. -On the other hand, `typing.Optional[float]` would mean the value could be -a `float`, or the literal `None` value. + The reason for using this is in some places, there is a semantic difference + between specifying something as being [`None`][], i.e. "no value", and + having a default to specify that the value has just not been mentioned. The + main example of this is in [`hikari.api.rest.RESTClient.edit_message`][] endpoints + where the contents will only be changed if they are explicitly mentioned in the + call. Editing a message content and setting it to [`None`][] would be expected to + clear the content, whereas setting it to [`hikari.undefined.UNDEFINED`][] would be + expected to leave the value as it is without changing it. -The reason for using this is in some places, there is a semantic difference -between specifying something as being `None`, i.e. "no value", and -having a default to specify that the value has just not been mentioned. The -main example of this is in `edit` endpoints where the contents will only be -changed if they are explicitly mentioned in the call. Editing a message content -and setting it to `None` would be expected to clear the content, -whereas setting it to `UNDEFINED` would be expected to leave the value as it -is without changing it. + Consider `UndefinedOr[T]` semantically equivalent to `undefined` versus + `null` in JavaScript, or `Optional` versus `null` in Java and C#. -Consider `UndefinedOr[T]` semantically equivalent to `undefined` versus -`null` in JavaScript, or `Optional` versus `null` in Java and C#. -If in doubt, remember: +!!! note + If in doubt, remember: -- `UNDEFINED` means there is no value present, or that it has been left to - the default value. -- `None` means the value is present and explicitly empty/null/void, - where this has a deterministic documented behaviour and no differentiation - is made between a `None` value, and one that has been omitted. + - [`hikari.undefined.UNDEFINED`][] means there is no value present, or that it has + been left to the default value, whatever that would be. + - [`None`][] means the value is present and explicitly empty/null/void, + where this has a deterministic documented behaviour and no differentiation + is made between a [`None`][] value, and one that has been omitted. """ UndefinedNoneOr = typing.Union[UndefinedOr[T], None] -"""Type hint for a value that may be `undefined.UNDEFINED`, or `None`. +"""Type hint for a value that may be [hikari.undefined.UNDEFINED], or [`None`][]. `UndefinedNoneOr[T]` is simply an alias for `UndefinedOr[typing.Optional[T]]`, which would expand to @@ -128,15 +129,15 @@ def __new__(cls: UndefinedType) -> typing.NoReturn: # pragma: nocover def all_undefined(*items: typing.Any) -> bool: - """Get if all of the provided items are `UNDEFINED`.""" + """Get if all of the provided items are [`hikari.undefined.UNDEFINED`][].""" return all(item is UNDEFINED for item in items) def any_undefined(*items: typing.Any) -> bool: - """Get if any of the provided items are `UNDEFINED`.""" + """Get if any of the provided items are [`hikari.undefined.UNDEFINED`][].""" return any(item is UNDEFINED for item in items) def count(*items: typing.Any) -> int: - """Count the number of items that are provided that are `UNDEFINED`.""" + """Count the number of items that are provided that are [`hikari.undefined.UNDEFINED`][].""" return sum(item is UNDEFINED for item in items) diff --git a/hikari/undefined.pyi b/hikari/undefined.pyi index 6bfa7f8bdf..88cdb7f11a 100644 --- a/hikari/undefined.pyi +++ b/hikari/undefined.pyi @@ -20,7 +20,7 @@ # 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. -"""Typehints for `hikari.undefined`.""" +"""Typehints for [`hikari.undefined`][].""" import enum as __enum from typing import Any as __Any diff --git a/hikari/users.py b/hikari/users.py index d6e44162a7..25b2b5ca26 100644 --- a/hikari/users.py +++ b/hikari/users.py @@ -124,12 +124,12 @@ 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`. + 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 + For full user info, consider calling the [`hikari.users.PartialUser.fetch_self`][] method to perform an API call. """ @@ -143,24 +143,24 @@ def app(self) -> traits.RESTAware: @property @abc.abstractmethod def avatar_hash(self) -> undefined.UndefinedNoneOr[str]: - """Avatar hash for the user, if they have one, otherwise `None`.""" + """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 `None`.""" + """Banner hash for the user, if they have one, otherwise [`None`][].""" @property @abc.abstractmethod def accent_color(self) -> undefined.UndefinedNoneOr[colors.Color]: - """Custom banner color for the user if set, else `None`. + """Custom banner color for the user if set, else [`None`][]. The official client will decide the default color if not set. """ @property def accent_colour(self) -> undefined.UndefinedNoneOr[colors.Color]: - """Alias for the `accent_color` field.""" + """Alias for the [`hikari.users.PartialUser.accent_color`][] field.""" return self.accent_color @property @@ -168,7 +168,7 @@ def accent_colour(self) -> undefined.UndefinedNoneOr[colors.Color]: def discriminator(self) -> undefined.UndefinedOr[str]: """Discriminator for the user. - .. deprecated:: 2.0.0.dev120 + !!! deprecated 2.0.0.dev120 Discriminators are deprecated and being replaced with "0" by Discord during username migration. This field will be removed after migration is complete. Learn more here: https://dis.gd/usernames @@ -182,7 +182,7 @@ def username(self) -> undefined.UndefinedOr[str]: @property @abc.abstractmethod def global_name(self) -> undefined.UndefinedNoneOr[str]: - """Global name for the user, if they have one, otherwise `None`.""" + """Global name for the user, if they have one, otherwise [`None`][].""" @property @abc.abstractmethod @@ -206,10 +206,10 @@ def mention(self) -> str: Examples -------- - .. code-block:: python - + ```py >>> some_user.mention '<@123456789123456789>' + ``` """ async def fetch_dm_channel(self) -> channels.DMChannel: @@ -283,15 +283,15 @@ async def send( ---------- content : hikari.undefined.UndefinedOr[typing.Any] If provided, the message contents. If - `hikari.undefined.UNDEFINED`, then nothing will be sent + [`hikari.undefined.UNDEFINED`][], then nothing will be sent in the content. Any other value here will be cast to a - `str`. + [`str`][]. - If this is a `hikari.embeds.Embed` and no `embed` nor `embeds` kwarg + 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 + 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. @@ -304,26 +304,26 @@ async def send( Attachments can be passed as many different things, to aid in convenience. - - If a `pathlib.PurePath` or `str` to a valid URL, the + - 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. + [`hikari.files.WebResource`][] such as + [`hikari.files.URL`][], + [`hikari.messages.Attachment`][], + [`hikari.emojis.Emoji`][], + [`hikari.embeds.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` + - 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 + - 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 + 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]] @@ -346,7 +346,6 @@ async def send( reply_must_exist : hikari.undefined.UndefinedOr[bool] If provided, whether to error if the message being replied to does not exist instead of sending as a normal (non-reply) message. - Defaults to `True`. This will not do anything if not being used with `reply`. mentions_everyone : hikari.undefined.UndefinedOr[bool] @@ -358,27 +357,27 @@ async def send( 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 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 + [`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 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 + [`hikari.snowflakes.Snowflake`][], or + [`hikari.guilds.PartialRole`][] derivatives to enforce mentioning specific roles. flags : hikari.undefined.UndefinedOr[hikari.messages.MessageFlag] If provided, optional flags to set on the message. If - `hikari.undefined.UNDEFINED`, then nothing is changed. + [`hikari.undefined.UNDEFINED`][], then nothing is changed. Note that some flags may not be able to be set. Currently the only - flags that can be set are `NONE` and `SUPPRESS_EMBEDS`. + flags that can be set are [`hikari.messages.MessageFlag.NONE`][] and [`hikari.messages.MessageFlag.SUPPRESS_EMBEDS`][]. Returns ------- @@ -402,7 +401,7 @@ async def send( 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 + If you are missing the [`hikari.permissions.Permissions.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. @@ -455,40 +454,40 @@ def app(self) -> traits.RESTAware: @property @abc.abstractmethod def accent_color(self) -> typing.Optional[colors.Color]: - """The custom banner color for the user, if set else `None`. + """The custom banner color for the user, if set else [`None`][]. The official client will decide the default color if not set. """ @property def accent_colour(self) -> typing.Optional[colors.Color]: - """Alias for the `accent_color` field.""" + """Alias for the [`hikari.users.User.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`.""" + """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. + May be [`None`][] if no custom avatar is set. In this case, you + should use [`hikari.User.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 `None`.""" + """Banner hash for the user, if they have one, otherwise [`None`][].""" @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. + May be [`None`][] if no custom banner is set. """ return self.make_banner_url() @@ -514,7 +513,7 @@ def display_avatar_url(self) -> files.URL: def discriminator(self) -> str: """Discriminator for the user. - .. deprecated:: 2.0.0.dev120 + !!! deprecated 2.0.0.dev120 Discriminators are deprecated and being replaced with "0" by Discord during username migration. This field will be removed after migration is complete. Learn more here: https://dis.gd/usernames @@ -542,10 +541,10 @@ def mention(self) -> str: Examples -------- - .. code-block:: python - + ```py >>> some_user.mention '<@123456789123456789>' + ``` """ @property @@ -556,34 +555,34 @@ def username(self) -> str: @property @abc.abstractmethod def global_name(self) -> typing.Optional[str]: - """Global name for the user, if they have one, otherwise `None`.""" + """Global name for the user, if they have one, otherwise [`None`][].""" 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. + If no custom avatar is set, this returns [`None`][]. You can then + use the [`hikari.User.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`. + The ext to use for this URL. 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 + 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. + The size to set for the URL. + 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. + The URL to the avatar, or [`None`][] if not present. Raises ------ @@ -606,25 +605,25 @@ def make_avatar_url(self, *, ext: typing.Optional[str] = None, size: int = 4096) 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`. + 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`. + The ext to use for this URL. Supports `png`, `jpeg`, `jpg`, `webp` and `gif` (when animated). - If `None`, then the correct default extension is + 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. + The size to set for the URL. + 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. + The URL to the banner, or [`None`][] if not present. Raises ------ @@ -651,7 +650,7 @@ 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, which will be denoted by `hikari.undefined.UNDEFINED`. + present, which will be denoted by [`hikari.undefined.UNDEFINED`][]. """ id: snowflakes.Snowflake = attrs.field(hash=True, repr=True) @@ -665,7 +664,7 @@ class PartialUserImpl(PartialUser): discriminator: undefined.UndefinedOr[str] = attrs.field(eq=False, hash=False, repr=True) """Four-digit discriminator for the user if unmigrated. - .. deprecated:: 2.0.0.dev120 + !!! deprecated 2.0.0.dev120 Discriminators are deprecated and being replaced with "0" by Discord during username migration. This field will be removed after migration is complete. Learn more here: https://dis.gd/usernames @@ -704,10 +703,10 @@ def mention(self) -> str: Examples -------- - .. code-block:: python - + ```py >>> some_user.mention '<@123456789123456789>' + ``` """ return f"<@{self.id}>" @@ -726,7 +725,7 @@ class UserImpl(PartialUserImpl, User): discriminator: str = attrs.field(eq=False, hash=False, repr=True) """The user's discriminator. - .. deprecated:: 2.0.0.dev120 + !!! deprecated 2.0.0.dev120 Discriminators are deprecated and being replaced with "0" by Discord during username migration. This field will be removed after migration is complete. Learn more here: https://dis.gd/usernames @@ -739,10 +738,10 @@ class UserImpl(PartialUserImpl, User): """The user's global name.""" avatar_hash: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) - """The user's avatar hash, if they have one, otherwise `None`.""" + """The user's avatar hash, if they have one, otherwise [`None`][].""" banner_hash: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) - """Banner hash of the user, if they have one, otherwise `None`""" + """Banner hash of the user, if they have one, otherwise [`None`][]""" accent_color: typing.Optional[colors.Color] = attrs.field(eq=False, hash=False, repr=False) """The custom banner color for the user, if set. @@ -751,10 +750,10 @@ class UserImpl(PartialUserImpl, User): """ is_bot: bool = attrs.field(eq=False, hash=False, repr=True) - """`True` if this user is a bot account, `False` otherwise.""" + """[`True`][] if this user is a bot account, [`False`][] otherwise.""" is_system: bool = attrs.field(eq=False, hash=False, repr=True) - """`True` if this user is a system account, `False` otherwise.""" + """[`True`][] if this user is a system account, [`False`][] otherwise.""" flags: UserFlag = attrs.field(eq=False, hash=False, repr=True) """The public flags for this user.""" @@ -776,21 +775,21 @@ class OwnUser(UserImpl): is_verified: typing.Optional[bool] = attrs.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` + Will be [`None`][] if retrieved through the OAuth2 flow without the `email` scope. """ email: typing.Optional[str] = attrs.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. + 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] = attrs.field(eq=False, hash=False, repr=False) """The type of Nitro Subscription this user account had. - This will always be `None` for bots. + This will always be [`None`][] for bots. """ async def fetch_self(self) -> OwnUser: diff --git a/hikari/voices.py b/hikari/voices.py index eef201d262..95ddcef16d 100644 --- a/hikari/voices.py +++ b/hikari/voices.py @@ -53,7 +53,7 @@ class VoiceState: channel_id: typing.Optional[snowflakes.Snowflake] = attrs.field(eq=False, hash=False, repr=True) """The ID of the channel this user is connected to. - This will be `None` if they are leaving voice. + This will be [`None`][] if they are leaving voice. """ guild_id: snowflakes.Snowflake = attrs.field(eq=False, hash=False, repr=True) @@ -96,7 +96,7 @@ class VoiceState: requested_to_speak_at: typing.Optional[datetime.datetime] = attrs.field(eq=False, hash=False, repr=True) """When the user requested to speak in a stage channel. - Will be `None` if they have not requested to speak. + Will be [`None`][] if they have not requested to speak. """ @@ -108,7 +108,7 @@ class VoiceRegion: id: str = attrs.field(hash=True, repr=True) """The string ID of this region. - .. note:: + !!! note Unlike most parts of this API, this ID will always be a string type. This is intentional. """ diff --git a/hikari/webhooks.py b/hikari/webhooks.py index 261e0191bc..d5abca14f5 100644 --- a/hikari/webhooks.py +++ b/hikari/webhooks.py @@ -92,9 +92,9 @@ def webhook_id(self) -> snowflakes.Snowflake: def token(self) -> typing.Optional[str]: """Webhook's token. - .. note:: - If this is `None` then the methods provided by `ExecutableWebhook` - will always raise a `ValueError`. + !!! note + If this is [`None`][] then the methods provided by [`hikari.webhooks.ExecutableWebhook`][] + will always raise a [`ValueError`][]. """ async def execute( @@ -121,27 +121,27 @@ async def execute( ) -> messages_.Message: """Execute the webhook to create a message. - .. warning:: + !!! warning At the time of writing, `username` and `avatar_url` are ignored for interaction webhooks. - Additionally, `SUPPRESS_EMBEDS`, `SUPPRESS_NOTIFICATIONS` and `EPHEMERAL` - are the only flags that can be set, with `EPHEMERAL` limited to + Additionally, [`hikari.messages.MessageFlag.SUPPRESS_EMBEDS`][], [`hikari.messages.MessageFlag.SUPPRESS_NOTIFICATIONS`][] and [`hikari.messages.MessageFlag.EPHEMERAL`][] + are the only flags that can be set, with [`hikari.messages.MessageFlag.EPHEMERAL`][] being limited to interaction webhooks. Parameters ---------- content : hikari.undefined.UndefinedOr[typing.Any] If provided, the message contents. If - `hikari.undefined.UNDEFINED`, then nothing will be sent + [`hikari.undefined.UNDEFINED`][], then nothing will be sent in the content. Any other value here will be cast to a - `str`. + [`str`][]. - If this is a `hikari.embeds.Embed` and no `embed` kwarg is - provided, then this will instead update the embed. This allows for - simpler syntax when sending an embed alone. + If this is a [`hikari.embeds.Embed`][] and no `embed` and no `embeds` + kwargs are 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 + 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. @@ -174,18 +174,18 @@ async def execute( If provided, whether the message should parse @everyone/@here mentions. user_mentions : hikari.undefined.UndefinedOr[typing.Union[hikari.snowflakes.SnowflakeishSequence[hikari.users.PartialUser], bool]] - If provided, and `True`, all mentions will be parsed. - If provided, and `False`, no mentions will be parsed. + If provided, and [`True`][], all mentions will be parsed. + If provided, and [`False`][], no mentions will be parsed. Alternatively this may be a collection of - `hikari.snowflakes.Snowflake`, or - `hikari.users.PartialUser` derivatives to enforce mentioning + [`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 mentions will be parsed. - If provided, and `False`, no mentions will be parsed. + If provided, and [`True`][], all mentions will be parsed. + If provided, and [`False`][], no mentions will be parsed. Alternatively this may be a collection of - `hikari.snowflakes.Snowflake`, or - `hikari.guilds.PartialRole` derivatives to enforce mentioning + [`hikari.snowflakes.Snowflake`][], or + [`hikari.guilds.PartialRole`][] derivatives to enforce mentioning specific roles. flags : typing.Union[hikari.undefined.UndefinedType, int, hikari.messages.MessageFlag] The flags to set for this webhook message. @@ -209,9 +209,7 @@ async def execute( hikari.errors.UnauthorizedError If you pass a token that's invalid for the target webhook. ValueError - If either `ExecutableWebhook.token` is `None` or more than 100 unique - objects/entities are passed for `role_mentions` or `user_mentions` or - if `token` is not available. + If `token` is not available. TypeError If both `attachment` and `attachments`, `component` and `components` or `embed` and `embeds` are specified. @@ -255,7 +253,7 @@ async def fetch_message(self, message: snowflakes.SnowflakeishOr[messages_.Messa Raises ------ ValueError - If `token` is not available. + If [`token`][] is not available. hikari.errors.UnauthorizedError If you are unauthorized to make the request (invalid/missing token). hikari.errors.NotFoundError @@ -298,16 +296,16 @@ async def edit_message( ) -> messages_.Message: """Edit a message sent by a webhook. - .. note:: + !!! note Mentioning everyone, roles, or users in message edits currently will not send a push notification showing a new mention to people on Discord. It will still highlight in their chat as if they were mentioned, however. - .. warning:: + !!! warning If you specify a text `content`, `mentions_everyone`, `mentions_reply`, `user_mentions`, and `role_mentions` will default - to `False` as the message will be re-parsed for mentions. This will + to [`False`][] as the message will be re-parsed for mentions. This will also occur if only one of the four are specified This is a limitation of Discord's design. If in doubt, specify all @@ -320,75 +318,75 @@ async def edit_message( an existing message. content : hikari.undefined.UndefinedNoneOr[typing.Any] If provided, the message contents. If - `hikari.undefined.UNDEFINED`, then nothing will be sent + [`hikari.undefined.UNDEFINED`][], then nothing will be sent in the content. Any other value here will be cast to a - `str`. + [`str`][]. - If this is a `hikari.embeds.Embed` and no `embed` nor - no `embeds` kwarg is provided, then this will instead + 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. + Likewise, if this is a [`hikari.files.Resource`][], then the + content is instead treated as an attachment if no `attachment` nor + `attachments` kwargs are provided. Other Parameters ---------------- attachment : hikari.undefined.UndefinedNoneOr[typing.Union[hikari.files.Resourceish, hikari.messages.Attachment]] If provided, the attachment to set on the message. If - `hikari.undefined.UNDEFINED`, the previous attachment, if - present, is not changed. If this is `None`, then the + [`hikari.undefined.UNDEFINED`][], the previous attachment, if + present, is not changed. If this is [`None`][], then the attachment is removed, if present. Otherwise, the new attachment that was provided will be attached. attachments : hikari.undefined.UndefinedNoneOr[typing.Sequence[typing.Union[hikari.files.Resourceish, hikari.messages.Attachment]]] If provided, the attachments to set on the message. If - `hikari.undefined.UNDEFINED`, the previous attachments, if - present, are not changed. If this is `None`, then the + [`hikari.undefined.UNDEFINED`][], the previous attachments, if + present, are not changed. If this is [`None`][], then the attachments is removed, if present. Otherwise, the new attachments that were provided will be attached. component : hikari.undefined.UndefinedNoneOr[hikari.api.special_endpoints.ComponentBuilder] If provided, builder object of the component to set for this message. This component will replace any previously set components and passing - `None` will remove all components. + [`None`][] will remove all components. components : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.api.special_endpoints.ComponentBuilder]] If provided, a sequence of the component builder objects set for this message. These components will replace any previously set - components and passing `None` or an empty sequence will + components and passing [`None`][] or an empty sequence will remove all components. embed : hikari.undefined.UndefinedNoneOr[hikari.embeds.Embed] If provided, the embed to set on the message. If - `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed. - If this is `None` then any present embeds are removed. + [`hikari.undefined.UNDEFINED`][], the previous embed(s) are not changed. + If this is [`None`][] then any present embeds are removed. Otherwise, the new embed that was provided will be used as the replacement. embeds : hikari.undefined.UndefinedNoneOr[typing.Sequence[hikari.embeds.Embed]] If provided, the embeds to set on the message. If - `hikari.undefined.UNDEFINED`, the previous embed(s) are not changed. - If this is `None` then any present embeds are removed. + [`hikari.undefined.UNDEFINED`][], the previous embed(s) are not changed. + If this is [`None`][] then any present embeds are removed. Otherwise, the new embeds that were provided will be used as the replacement. mentions_everyone : hikari.undefined.UndefinedOr[bool] If provided, sanitation for `@everyone` mentions. If - `hikari.undefined.UNDEFINED`, then the previous setting is - not changed. If `True`, then `@everyone`/`@here` mentions + [`hikari.undefined.UNDEFINED`][], then the previous setting is + not changed. If [`True`][], then `@everyone`/`@here` mentions in the message content will show up as mentioning everyone that can view the chat. 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 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 + [`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 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 + [`hikari.snowflakes.Snowflake`][], or + [`hikari.guilds.PartialRole`][] derivatives to enforce mentioning specific roles. Returns @@ -500,17 +498,17 @@ def __str__(self) -> str: def mention(self) -> str: """Return a raw mention string for the given webhook's user. - .. note:: + !!! note This exists purely for consistency. Webhooks do not receive events from the gateway, and without some bot backend to support it, will not be able to detect mentions of their webhook. Examples -------- - .. code-block:: python - + ```py >>> some_webhook.mention '<@123456789123456789>' + ``` """ return f"<@{self.id}>" @@ -518,7 +516,7 @@ def mention(self) -> str: def avatar_url(self) -> typing.Optional[files_.URL]: """URL for this webhook's avatar, if set. - May be `None` if no avatar is set. In this case, you should use + May be [`None`][] if no avatar is set. In this case, you should use `default_avatar_url` instead. """ return self.make_avatar_url() @@ -531,23 +529,23 @@ def default_avatar_url(self) -> files_.URL: def make_avatar_url(self, ext: str = "png", size: int = 4096) -> typing.Optional[files_.URL]: """Generate the avatar URL for this webhook's custom avatar if set. - If no avatar is specified, return `None`. In this case, you should + If no avatar is specified, return [`None`][]. In this case, you should use `default_avatar` instead. Parameters ---------- ext : str - The extension to use for this URL, defaults to `png`. + The extension to use for this URL. Supports `png`, `jpeg`, `jpg` and `webp`. size : int - The size to set for the URL, defaults to `4096`. - Can be any power of two between 16 and 4096. + The size to set for the URL. + Can be any power of two between `16` and `4096`. Will be ignored for default avatars. Returns ------- typing.Optional[hikari.files.URL] - The URL of the resource. `None` if no avatar is set (in + The URL of the resource. [`None`][] if no avatar is set (in this case, use the `default_avatar` instead). Raises @@ -581,15 +579,15 @@ class IncomingWebhook(PartialWebhook, ExecutableWebhook): author: typing.Optional[users_.User] = attrs.field(eq=False, hash=False, repr=True) """The user that created the webhook. - .. note:: - This will be `None` when fetched with the webhook's token + !!! note + This will be [`None`][] when fetched with the webhook's token rather than bot authorization or when received within audit logs. """ token: typing.Optional[str] = attrs.field(eq=False, hash=False, repr=False) """The token for the webhook. - .. note:: + !!! note This is only available for incoming webhooks that are created in the channel settings. """ @@ -605,8 +603,8 @@ async def delete(self, *, use_token: undefined.UndefinedOr[bool] = undefined.UND Other Parameters ---------------- use_token : hikari.undefined.UndefinedOr[bool] - If set to `True` then the webhook's token will be used for - this request; if set to `False` then bot authorization will + If set to [`True`][] then the webhook's token will be used for + this request; if set to [`False`][] then bot authorization will be used; if not specified then the webhook's token will be used for the request if it's set else bot authorization. @@ -615,11 +613,11 @@ async def delete(self, *, use_token: undefined.UndefinedOr[bool] = undefined.UND hikari.errors.NotFoundError If this webhook is not found. hikari.errors.ForbiddenError - If you either lack the `MANAGE_WEBHOOKS` permission or + If you either lack the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission or are not a member of the guild this webhook belongs to. ValueError - If `use_token` is passed as `True` when `IncomingWebhook.token` is - `None`. + If `use_token` is passed as [`True`][] when [`hikari.webhooks.IncomingWebhook.token`][] is + [`None`][]. """ token: undefined.UndefinedOr[str] = undefined.UNDEFINED if use_token: @@ -648,7 +646,7 @@ async def edit( name : hikari.undefined.UndefinedOr[str] If provided, the new name string. avatar : hikari.undefined.UndefinedOr[hikari.files.Resourceish] - If provided, the new avatar image. If `None`, then + If provided, the new avatar image. If [`None`][], then it is removed. If not specified, nothing is changed. channel : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.channels.WebhookChannelT]] If provided, the object or ID of the new channel the given @@ -658,8 +656,8 @@ async def edit( was performed. This field will be used when using the webhook's token rather than bot authorization. use_token : hikari.undefined.UndefinedOr[bool] - If set to `True` then the webhook's token will be used for - this request; if set to `False` then bot authorization will + If set to [`True`][] then the webhook's token will be used for + this request; if set to [`False`][] then bot authorization will be used; if not specified then the webhook's token will be used for the request if it's set else bot authorization. @@ -671,14 +669,14 @@ async def edit( Raises ------ ValueError - If `use_token` is passed as `True` when `IncomingWebhook.token` is `None`. + If `use_token` is passed as [`True`][] when [`hikari.webhooks.IncomingWebhook.token`][] is [`None`][]. hikari.errors.BadRequestError If any invalid snowflake IDs are passed; a snowflake may be invalid - due to it being outside of the range of a 64 bit integer. + due to it being outside the range of a 64-bit integer. hikari.errors.NotFoundError If either the webhook or the channel are not found. hikari.errors.ForbiddenError - If you either lack the `MANAGE_WEBHOOKS` permission or + If you either lack the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission or are not a member of the guild this webhook belongs to. hikari.errors.UnauthorizedError If you pass a token that's invalid for the target webhook. @@ -735,8 +733,8 @@ async def fetch_self(self, *, use_token: undefined.UndefinedOr[bool] = undefined Other Parameters ---------------- use_token : hikari.undefined.UndefinedOr[bool] - If set to `True` then the webhook's token will be used for - this request; if set to `False` then bot authorization will + If set to [`True`][] then the webhook's token will be used for + this request; if set to [`False`][] then bot authorization will be used; if not specified then the webhook's token will be used for the request if it's set else bot authorization. @@ -748,11 +746,11 @@ async def fetch_self(self, *, use_token: undefined.UndefinedOr[bool] = undefined Raises ------ ValueError - If `use_token` is passed as `True` when `Webhook.token` - is `None`. + If `use_token` is passed as [`True`][] when [`hikari.webhooks.IncomingWebhook.token`][] + is [`None`][]. hikari.errors.ForbiddenError If you're not in the guild that owns this webhook or - lack the `MANAGE_WEBHOOKS` permission. + lack the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission. hikari.errors.NotFoundError If the webhook is not found. hikari.errors.UnauthorizedError @@ -790,21 +788,21 @@ class ChannelFollowerWebhook(PartialWebhook): author: typing.Optional[users_.User] = attrs.field(eq=False, hash=False, repr=True) """The user that created the webhook. - .. note:: - This will be `None` when received within an audit log. + !!! note + This will be [`None`][] when received within an audit log. """ source_channel: typing.Optional[channels_.PartialChannel] = attrs.field(eq=False, hash=False, repr=True) """The partial object of the channel this webhook is following. - This will be `None` when the user that followed the channel is no + This will be [`None`][] when the user that followed the channel is no longer in the source guild or has lost access to the source channel. """ source_guild: typing.Optional[guilds_.PartialGuild] = attrs.field(eq=False, hash=False, repr=True) """The partial object of the guild this webhook is following. - This will be `None` when the user that followed the channel is no + This will be [`None`][] when the user that followed the channel is no longer in the source guild or has lost access to the source channel. """ @@ -816,7 +814,7 @@ async def delete(self) -> None: hikari.errors.NotFoundError If this webhook is not found. hikari.errors.ForbiddenError - If you either lack the `MANAGE_WEBHOOKS` permission or + If you either lack the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission or are not a member of the guild this webhook belongs to. """ await self.app.rest.delete_webhook(self.id) @@ -836,7 +834,7 @@ async def edit( name : hikari.undefined.UndefinedOr[str] If provided, the new name string. avatar : hikari.undefined.UndefinedOr[hikari.files.Resourceish] - If provided, the new avatar image. If `None`, then + If provided, the new avatar image. If [`None`][], then it is removed. If not specified, nothing is changed. channel : hikari.undefined.UndefinedOr[hikari.snowflakes.SnowflakeishOr[hikari.channels.WebhookChannelT]] If provided, the object or ID of the new channel the given @@ -859,7 +857,7 @@ async def edit( hikari.errors.NotFoundError If either the webhook or the channel are not found. hikari.errors.ForbiddenError - If you either lack the `MANAGE_WEBHOOKS` permission or + If you either lack the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission or are not a member of the guild this webhook belongs to. hikari.errors.UnauthorizedError If you pass a token that's invalid for the target webhook. @@ -911,7 +909,7 @@ async def fetch_self(self) -> ChannelFollowerWebhook: ------ hikari.errors.ForbiddenError If you're not in the guild that owns this webhook or - lack the `MANAGE_WEBHOOKS` permission. + lack the [`hikari.permissions.Permissions.MANAGE_WEBHOOKS`][] permission. hikari.errors.NotFoundError If the webhook is not found. hikari.errors.UnauthorizedError diff --git a/mkdocs.yml b/mkdocs.yml new file mode 100644 index 0000000000..94cd3807cd --- /dev/null +++ b/mkdocs.yml @@ -0,0 +1,164 @@ +site_name: hikari +site_url: https://docs.hikari-py.dev/ +site_dir: public/docs + +repo_url: https://github.com/hikari-py/hikari/ +repo_name: hikari-py/hikari +edit_uri: blob/master/docs/ + +watch: [ hikari, README.md, CHANGELOG.md ] +copyright: © 2021-present davfsa + +#strict: true + +theme: + name: material + font: + code: JetBrains Mono + + logo: logo.png + favicon: logo.png + + icon: + repo: fontawesome/brands/github + edit: material/pencil + view: material/eye + admonition: + note: octicons/tag-16 + abstract: octicons/checklist-16 + info: octicons/info-16 + tip: octicons/squirrel-16 + success: octicons/check-16 + question: octicons/question-16 + warning: octicons/alert-16 + failure: octicons/x-circle-16 + danger: octicons/zap-16 + bug: octicons/bug-16 + example: octicons/beaker-16 + quote: octicons/quote-16 + + palette: + - media: "(prefers-color-scheme: light)" + scheme: default + primary: deep purple + accent: deep purple + toggle: + icon: material/toggle-switch + name: Switch to dark mode + + - media: "(prefers-color-scheme: dark)" + scheme: slate + primary: deep purple + accent: deep purple + toggle: + icon: material/toggle-switch-off-outline + name: Switch to light mode + + features: + - content.tabs.link + - search.highlight + - search.suggest + - search.share + - content.code.copy + - content.code.select + - content.code.annotate + - content.action.edit + - navigation.tabs + - navigation.indexes + - navigation.top + - navigation.tracking + - content.tooltips + - toc.follow + +markdown_extensions: + - abbr + - admonition + - attr_list + - def_list + - footnotes + - meta + - md_in_html + - pymdownx.details + - pymdownx.superfences + - toc: + permalink: "#" + + # Python Markdown Extensions + - pymdownx.snippets + - pymdownx.caret + - pymdownx.details + - pymdownx.inlinehilite + - pymdownx.keys + - pymdownx.mark + - pymdownx.superfences + - pymdownx.tilde + - pymdownx.emoji: + emoji_index: !!python/name:material.extensions.emoji.twemoji + emoji_generator: !!python/name:material.extensions.emoji.to_svg + - pymdownx.highlight: + anchor_linenums: true + line_spans: __span + pygments_lang_class: true + - pymdownx.betterem: + smart_enable: all + - pymdownx.tabbed: + alternate_style: true + combine_header_slug: true + slugify: !!python/object/apply:pymdownx.slugs.slugify + kwds: + case: lower + - pymdownx.tasklist: + custom_checkbox: true + +plugins: + - autorefs + - search + - glightbox: + touchNavigation: true + loop: false + effect: zoom + slide_effect: slide + width: 100% + height: auto + zoomable: true + draggable: true + auto_caption: false + caption_position: bottom + skip_classes: + - no-lightbox + - gen-files: + scripts: + - docs/gen_ref_pages.py + - literate-nav: + nav_file: summary.md + - mkdocstrings: + enabled: !ENV [ENABLE_MKDOCSTRINGS, true] + default_handler: python + enable_inventory: true + handlers: + python: + import: + - https://docs.python.org/3/objects.inv + - https://docs.aiohttp.org/en/stable/objects.inv + - https://www.attrs.org/en/stable/objects.inv + - https://multidict.readthedocs.io/en/stable/objects.inv + - https://yarl.readthedocs.io/en/stable/objects.inv + options: + filters: ["!^_"] + heading_level: 3 + annotations_path: brief + docstring_section_style: spacy + docstring_style: numpy + inherited_members: true + merge_init_into_class: true + separate_signature: true + show_signature_annotations: true + show_source: false + show_submodules: false + signature_crossrefs: true + show_symbol_type_heading: true + show_symbol_type_toc: true +# show_root_toc_entry: false + line_length: 80 + extensions: + - griffe_inherited_docstrings diff --git a/pipelines/config.py b/pipelines/config.py index 15a937e475..283dfa7c57 100644 --- a/pipelines/config.py +++ b/pipelines/config.py @@ -35,6 +35,7 @@ FLAKE8_REPORT = _os.path.join(ARTIFACT_DIRECTORY, "flake8") PYPROJECT_TOML = "pyproject.toml" COVERAGE_HTML_PATH = _os.path.join(ARTIFACT_DIRECTORY, "coverage", "html") +DOCUMENTATION_OUTPUT_PATH = _os.path.join(ARTIFACT_DIRECTORY, "docs") # Reformatting paths REFORMATTING_FILE_EXTS = ( diff --git a/pipelines/mkdocs.nox.py b/pipelines/mkdocs.nox.py new file mode 100644 index 0000000000..931470cfca --- /dev/null +++ b/pipelines/mkdocs.nox.py @@ -0,0 +1,49 @@ +# -*- coding: utf-8 -*- +# 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. +"""Documentation pages generation.""" +from pipelines import config +from pipelines import nox + + +@nox.session() +def mkdocs(session: nox.Session): + """Generate docs using mkdocs.""" + if "--no-refs" in session.posargs: + session.env["ENABLE_MKDOCSTRINGS"] = "false" + + session.install("-e", ".", *nox.dev_requirements("mkdocs")) + + session.run("mkdocs", "build", "-d", config.DOCUMENTATION_OUTPUT_PATH) + + +@nox.session() +def mkdocs_serve(session: nox.Session): + """Start an HTTP server that serves the generated docs in real time.""" + if "--no-refs" in session.posargs: + session.env["ENABLE_MKDOCSTRINGS"] = "false" + + session.install("-e", ".", *nox.dev_requirements("mkdocs")) + + if "--no-reload" in session.posargs: + session.run("mkdocs", "serve", "--no-livereload") + else: + session.run("mkdocs", "serve") diff --git a/pipelines/sphinx.nox.py b/pipelines/sphinx.nox.py deleted file mode 100644 index 41a3a4cf7d..0000000000 --- a/pipelines/sphinx.nox.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- coding: utf-8 -*- -# 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. -"""Website pages generation.""" -import contextlib -import functools -import http.server -import logging -import os -import socket -import threading -import webbrowser - -from pipelines import config -from pipelines import nox - - -@nox.session() -def sphinx(session: nox.Session): - """Generate docs using sphinx.""" - if "--no-refs" in session.posargs: - session.env["SKIP_REFERENCE_DOCS"] = "1" - - if not os.path.exists(config.ARTIFACT_DIRECTORY): - os.mkdir(config.ARTIFACT_DIRECTORY) - - session.install("-e", ".", *nox.dev_requirements("sphinx")) - - session.run( - "sphinx-build", "-M", "dirhtml", config.DOCUMENTATION_DIRECTORY, os.path.join(config.ARTIFACT_DIRECTORY, "docs") - ) - - -class RequestHandler(http.server.SimpleHTTPRequestHandler): - def __init__(self, *args, **kwargs): - directory = os.path.join(config.ARTIFACT_DIRECTORY, "docs", "dirhtml") - super().__init__(directory=directory, *args, **kwargs) - - def end_headers(self): - self.send_header("Cache-Control", "no-cache, no-store, must-revalidate") - self.send_header("Pragma", "no-cache") - self.send_header("Expires", "0") - super().end_headers() - - -class HTTPServerThread(threading.Thread): - def __init__(self) -> None: - logging.basicConfig(level="INFO") - - super().__init__(name="HTTP Server", daemon=True) - # Use a socket to obtain a random free port to host the HTTP server on. - with contextlib.closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock: - sock.bind(("", 0)) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - self.host, self.port = sock.getsockname() - - self.server = http.server.HTTPServer((self.host, self.port), RequestHandler) - - def run(self) -> None: - self.server.serve_forever() - - def close(self) -> None: - self.server.shutdown() - - -@nox.session(venv_backend="none") -def view_docs(_: nox.Session) -> None: - """Start an HTTP server for any generated pages in `/public/docs/dirhtml`.""" - with contextlib.closing(HTTPServerThread()) as thread: - thread.start() - webbrowser.open(f"http://{thread.host}:{thread.port}") - thread.join()