From 02b819cd0bd9073e34ef9595d09e5102a519edf2 Mon Sep 17 00:00:00 2001 From: Jakub Kuczys Date: Tue, 14 Apr 2026 18:31:59 +0200 Subject: [PATCH 01/10] Update ruff configuration to exclude docs/tests formatting --- .github/workflows/lint.yml | 2 +- pyproject.toml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 73992a155..2c9f648a8 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -45,4 +45,4 @@ jobs: - name: Run ruff if: ${{ always() && steps.install-deps.outcome == 'success' }} run: | - ruff format --check discord examples + ruff format --check diff --git a/pyproject.toml b/pyproject.toml index 37b5f5bc5..360676812 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -91,6 +91,7 @@ include-package-data = true [tool.ruff] line-length = 125 +extend-exclude = ["docs", "tests"] [tool.ruff.lint.isort] combine-as-imports = true From dae01425542db734c01903fa2de42f91758a5a3b Mon Sep 17 00:00:00 2001 From: Pipythonmc <47196755+pythonmcpi@users.noreply.github.com> Date: Tue, 14 Apr 2026 09:32:31 -0700 Subject: [PATCH 02/10] Change the default 'required' value to True for all select variants Fixes #10339 --- discord/ui/select.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/discord/ui/select.py b/discord/ui/select.py index 4c516358a..baa1e4df8 100644 --- a/discord/ui/select.py +++ b/discord/ui/select.py @@ -241,7 +241,7 @@ class BaseSelect(Item[V]): min_values: Optional[int] = None, max_values: Optional[int] = None, disabled: bool = False, - required: bool = False, + required: bool = True, options: List[SelectOption] = MISSING, channel_types: List[ChannelType] = MISSING, default_values: Sequence[SelectDefaultValue] = MISSING, @@ -640,7 +640,7 @@ class UserSelect(BaseSelect[V]): min_values: int = 1, max_values: int = 1, disabled: bool = False, - required: bool = False, + required: bool = True, row: Optional[int] = None, default_values: Sequence[ValidDefaultValues] = MISSING, id: Optional[int] = None, @@ -748,7 +748,7 @@ class RoleSelect(BaseSelect[V]): min_values: int = 1, max_values: int = 1, disabled: bool = False, - required: bool = False, + required: bool = True, row: Optional[int] = None, default_values: Sequence[ValidDefaultValues] = MISSING, id: Optional[int] = None, @@ -852,7 +852,7 @@ class MentionableSelect(BaseSelect[V]): min_values: int = 1, max_values: int = 1, disabled: bool = False, - required: bool = False, + required: bool = True, row: Optional[int] = None, default_values: Sequence[ValidDefaultValues] = MISSING, id: Optional[int] = None, @@ -966,7 +966,7 @@ class ChannelSelect(BaseSelect[V]): min_values: int = 1, max_values: int = 1, disabled: bool = False, - required: bool = False, + required: bool = True, row: Optional[int] = None, default_values: Sequence[ValidDefaultValues] = MISSING, id: Optional[int] = None, From f0195a5ffbc7a451a08180c9072d281c422f60fa Mon Sep 17 00:00:00 2001 From: Jakub Kuczys Date: Tue, 14 Apr 2026 18:37:51 +0200 Subject: [PATCH 03/10] Remove datetime.utcnow() use (deprecated since 3.12) --- discord/member.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/discord/member.py b/discord/member.py index ad3c300af..59c181724 100644 --- a/discord/member.py +++ b/discord/member.py @@ -977,7 +977,7 @@ class Member(discord.abc.Messageable, _UserTag): await http.edit_my_voice_state(guild_id, voice_state_payload) else: if not suppress: - voice_state_payload['request_to_speak_timestamp'] = datetime.datetime.utcnow().isoformat() + voice_state_payload['request_to_speak_timestamp'] = utils.utcnow().isoformat() await http.edit_voice_state(guild_id, self.id, voice_state_payload) if voice_channel is not MISSING: @@ -1038,7 +1038,7 @@ class Member(discord.abc.Messageable, _UserTag): payload = { 'channel_id': self.voice.channel.id, - 'request_to_speak_timestamp': datetime.datetime.utcnow().isoformat(), + 'request_to_speak_timestamp': utils.utcnow().isoformat(), } if self._state.self_id != self.id: From 85144ec5e42533ab1d13b18c1bf56ea482733f47 Mon Sep 17 00:00:00 2001 From: Rapptz Date: Tue, 14 Apr 2026 13:19:40 -0400 Subject: [PATCH 04/10] Fix ActionRow remove and add item not using Item.width --- discord/ui/action_row.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/discord/ui/action_row.py b/discord/ui/action_row.py index 38fc3daaa..863564973 100644 --- a/discord/ui/action_row.py +++ b/discord/ui/action_row.py @@ -274,7 +274,7 @@ class ActionRow(Item[V]): item._update_view(self.view) item._parent = self - self._weight += 1 + self._weight += item.width self._children.append(item) return self @@ -298,7 +298,7 @@ class ActionRow(Item[V]): else: if self._view: self._view._add_count(-1) - self._weight -= 1 + self._weight -= item.width return self From 3270121c8098539fa8420ce89104943e3adb88e2 Mon Sep 17 00:00:00 2001 From: Jakub Kuczys Date: Tue, 14 Apr 2026 20:46:19 +0200 Subject: [PATCH 05/10] Use iscoroutinefunction from inspect instead of asyncio on 3.12+ --- discord/app_commands/commands.py | 27 ++++++++++++++++++--------- discord/app_commands/transformers.py | 4 ++-- discord/app_commands/tree.py | 8 ++++---- discord/client.py | 4 ++-- discord/ext/commands/bot.py | 9 ++++----- discord/ext/commands/cog.py | 6 +++--- discord/ext/commands/core.py | 14 +++++++------- discord/ext/tasks/__init__.py | 10 +++++----- discord/member.py | 3 +-- discord/ui/button.py | 4 ++-- discord/ui/select.py | 5 ++--- discord/utils.py | 9 +++++++++ 12 files changed, 59 insertions(+), 44 deletions(-) diff --git a/discord/app_commands/commands.py b/discord/app_commands/commands.py index da8879827..4000f2968 100644 --- a/discord/app_commands/commands.py +++ b/discord/app_commands/commands.py @@ -58,7 +58,16 @@ from ..message import Message from ..user import User from ..member import Member from ..permissions import Permissions -from ..utils import resolve_annotation, MISSING, is_inside_class, maybe_coroutine, async_all, _shorten, _to_kebab_case +from ..utils import ( + resolve_annotation, + MISSING, + is_inside_class, + maybe_coroutine, + async_all, + _iscoroutinefunction, + _shorten, + _to_kebab_case, +) if TYPE_CHECKING: from typing_extensions import ParamSpec, Concatenate, Unpack @@ -346,7 +355,7 @@ def _populate_autocomplete(params: Dict[str, CommandParameter], autocomplete: Di if callback is MISSING: continue - if not inspect.iscoroutinefunction(callback): + if not _iscoroutinefunction(callback): raise TypeError('autocomplete callback must be a coroutine function') if param.type not in (AppCommandOptionType.string, AppCommandOptionType.number, AppCommandOptionType.integer): @@ -1037,7 +1046,7 @@ class Command(Generic[GroupT, P, T]): The coroutine passed is not actually a coroutine. """ - if not inspect.iscoroutinefunction(coro): + if not _iscoroutinefunction(coro): raise TypeError('The error handler must be a coroutine.') self.on_error = coro @@ -1098,7 +1107,7 @@ class Command(Generic[GroupT, P, T]): """ def decorator(coro: AutocompleteCallback[GroupT, ChoiceT]) -> AutocompleteCallback[GroupT, ChoiceT]: - if not inspect.iscoroutinefunction(coro): + if not _iscoroutinefunction(coro): raise TypeError('The autocomplete callback must be a coroutine function.') try: @@ -1347,7 +1356,7 @@ class ContextMenu: The coroutine passed is not actually a coroutine. """ - if not inspect.iscoroutinefunction(coro): + if not _iscoroutinefunction(coro): raise TypeError('The error handler must be a coroutine.') self.on_error = coro @@ -1840,7 +1849,7 @@ class Group: The coroutine passed is not actually a coroutine, or is an invalid coroutine. """ - if not inspect.iscoroutinefunction(coro): + if not _iscoroutinefunction(coro): raise TypeError('The error handler must be a coroutine.') params = inspect.signature(coro).parameters @@ -1990,7 +1999,7 @@ class Group: """ def decorator(func: CommandCallback[GroupT, P, T]) -> Command[GroupT, P, T]: - if not inspect.iscoroutinefunction(func): + if not _iscoroutinefunction(func): raise TypeError('command function must be a coroutine function') if description is MISSING: @@ -2051,7 +2060,7 @@ def command( """ def decorator(func: CommandCallback[GroupT, P, T]) -> Command[GroupT, P, T]: - if not inspect.iscoroutinefunction(func): + if not _iscoroutinefunction(func): raise TypeError('command function must be a coroutine function') if description is MISSING: @@ -2123,7 +2132,7 @@ def context_menu( """ def decorator(func: ContextMenuCallback) -> ContextMenu: - if not inspect.iscoroutinefunction(func): + if not _iscoroutinefunction(func): raise TypeError('context menu function must be a coroutine function') actual_name = func.__name__.title() if name is MISSING else name diff --git a/discord/app_commands/transformers.py b/discord/app_commands/transformers.py index 531f06e66..3a6665634 100644 --- a/discord/app_commands/transformers.py +++ b/discord/app_commands/transformers.py @@ -53,7 +53,7 @@ from ..channel import StageChannel, VoiceChannel, TextChannel, CategoryChannel, from ..abc import GuildChannel from ..threads import Thread from ..enums import Enum as InternalEnum, AppCommandOptionType, ChannelType, Locale -from ..utils import MISSING, maybe_coroutine, _human_join, TIMESTAMP_PATTERN +from ..utils import MISSING, maybe_coroutine, _human_join, _iscoroutinefunction, TIMESTAMP_PATTERN from ..user import User from ..role import Role from ..member import Member @@ -814,7 +814,7 @@ def get_supported_annotation( params = inspect.signature(transform_classmethod.__func__).parameters if len(params) != 3: raise TypeError('Inline transformer with transform classmethod requires 3 parameters') - if not inspect.iscoroutinefunction(transform_classmethod.__func__): + if not _iscoroutinefunction(transform_classmethod.__func__): raise TypeError('Inline transformer with transform classmethod must be a coroutine') return (InlineTransformer(annotation), MISSING, False) diff --git a/discord/app_commands/tree.py b/discord/app_commands/tree.py index 4db1d83f6..9350af4d6 100644 --- a/discord/app_commands/tree.py +++ b/discord/app_commands/tree.py @@ -62,7 +62,7 @@ from .installs import AppCommandContext, AppInstallationType from .translator import Translator, locale_str from ..errors import ClientException, HTTPException from ..enums import AppCommandType, InteractionType -from ..utils import MISSING, _get_as_snowflake, _is_submodule, _shorten +from ..utils import MISSING, _get_as_snowflake, _iscoroutinefunction, _is_submodule, _shorten from .._types import ClientT @@ -839,7 +839,7 @@ class CommandTree(Generic[ClientT]): not match the signature. """ - if not inspect.iscoroutinefunction(coro): + if not _iscoroutinefunction(coro): raise TypeError('The error handler must be a coroutine.') params = inspect.signature(coro).parameters @@ -908,7 +908,7 @@ class CommandTree(Generic[ClientT]): """ def decorator(func: CommandCallback[Group, P, T]) -> Command[Group, P, T]: - if not inspect.iscoroutinefunction(func): + if not _iscoroutinefunction(func): raise TypeError('command function must be a coroutine function') if description is MISSING: @@ -1005,7 +1005,7 @@ class CommandTree(Generic[ClientT]): """ def decorator(func: ContextMenuCallback) -> ContextMenu: - if not inspect.iscoroutinefunction(func): + if not _iscoroutinefunction(func): raise TypeError('context menu function must be a coroutine function') actual_name = func.__name__.title() if name is MISSING else name diff --git a/discord/client.py b/discord/client.py index 1c1ed9f48..cc77ae5f8 100644 --- a/discord/client.py +++ b/discord/client.py @@ -68,7 +68,7 @@ from .voice_client import VoiceClient from .http import HTTPClient from .state import ConnectionState from . import utils -from .utils import MISSING, time_snowflake, deprecated +from .utils import MISSING, time_snowflake, deprecated, _iscoroutinefunction from .object import Object from .backoff import ExponentialBackoff from .webhook import Webhook @@ -2098,7 +2098,7 @@ class Client: The coroutine passed is not actually a coroutine. """ - if not asyncio.iscoroutinefunction(coro): + if not _iscoroutinefunction(coro): raise TypeError('event registered must be a coroutine function') setattr(self, coro.__name__, coro) diff --git a/discord/ext/commands/bot.py b/discord/ext/commands/bot.py index 0bb4cf95f..46b5f5850 100644 --- a/discord/ext/commands/bot.py +++ b/discord/ext/commands/bot.py @@ -25,7 +25,6 @@ DEALINGS IN THE SOFTWARE. from __future__ import annotations -import asyncio import collections import collections.abc import inspect @@ -53,7 +52,7 @@ from typing import ( import discord from discord import app_commands from discord.app_commands.tree import _retrieve_guild_ids -from discord.utils import MISSING, _is_submodule +from discord.utils import MISSING, _iscoroutinefunction, _is_submodule from .core import GroupMixin from .view import StringView @@ -581,7 +580,7 @@ class BotBase(GroupMixin[None]): TypeError The coroutine passed is not actually a coroutine. """ - if not asyncio.iscoroutinefunction(coro): + if not _iscoroutinefunction(coro): raise TypeError('The pre-invoke hook must be a coroutine.') self._before_invoke = coro @@ -618,7 +617,7 @@ class BotBase(GroupMixin[None]): TypeError The coroutine passed is not actually a coroutine. """ - if not asyncio.iscoroutinefunction(coro): + if not _iscoroutinefunction(coro): raise TypeError('The post-invoke hook must be a coroutine.') self._after_invoke = coro @@ -654,7 +653,7 @@ class BotBase(GroupMixin[None]): """ name = func.__name__ if name is MISSING else name - if not asyncio.iscoroutinefunction(func): + if not _iscoroutinefunction(func): raise TypeError('Listeners must be coroutines') if name in self.extra_events: diff --git a/discord/ext/commands/cog.py b/discord/ext/commands/cog.py index e229345cc..7f553c42d 100644 --- a/discord/ext/commands/cog.py +++ b/discord/ext/commands/cog.py @@ -28,7 +28,7 @@ import inspect import discord import logging from discord import app_commands -from discord.utils import maybe_coroutine, _to_kebab_case +from discord.utils import maybe_coroutine, _iscoroutinefunction, _to_kebab_case from typing import ( Any, @@ -233,7 +233,7 @@ class CogMeta(type): if elem.startswith(('cog_', 'bot_')): raise TypeError(no_bot_cog.format(base, elem)) cog_app_commands[elem] = value - elif inspect.iscoroutinefunction(value): + elif _iscoroutinefunction(value): try: getattr(value, '__cog_listener__') except AttributeError: @@ -522,7 +522,7 @@ class Cog(metaclass=CogMeta): actual = func if isinstance(actual, staticmethod): actual = actual.__func__ - if not inspect.iscoroutinefunction(actual): + if not _iscoroutinefunction(actual): raise TypeError('Listener function must be a coroutine function.') actual.__cog_listener__ = True to_assign = name or actual.__name__ diff --git a/discord/ext/commands/core.py b/discord/ext/commands/core.py index 949539b61..4adaf1fb1 100644 --- a/discord/ext/commands/core.py +++ b/discord/ext/commands/core.py @@ -427,7 +427,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]): /, **kwargs: Unpack[_CommandKwargs], ) -> None: - if not asyncio.iscoroutinefunction(func): + if not discord.utils._iscoroutinefunction(func): raise TypeError('Callback must be a coroutine.') name = kwargs.get('name') or func.__name__ @@ -1102,7 +1102,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]): The coroutine passed is not actually a coroutine. """ - if not asyncio.iscoroutinefunction(coro): + if not discord.utils._iscoroutinefunction(coro): raise TypeError('The error handler must be a coroutine.') self.on_error: Error[CogT, Any] = coro @@ -1140,7 +1140,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]): TypeError The coroutine passed is not actually a coroutine. """ - if not asyncio.iscoroutinefunction(coro): + if not discord.utils._iscoroutinefunction(coro): raise TypeError('The pre-invoke hook must be a coroutine.') self._before_invoke = coro @@ -1171,7 +1171,7 @@ class Command(_BaseCommand, Generic[CogT, P, T]): TypeError The coroutine passed is not actually a coroutine. """ - if not asyncio.iscoroutinefunction(coro): + if not discord.utils._iscoroutinefunction(coro): raise TypeError('The post-invoke hook must be a coroutine.') self._after_invoke = coro @@ -1945,7 +1945,7 @@ def check(predicate: UserCheck[ContextT], /) -> Check[ContextT]: return func - if inspect.iscoroutinefunction(predicate): + if discord.utils._iscoroutinefunction(predicate): decorator.predicate = predicate else: @@ -2369,7 +2369,7 @@ def guild_only() -> Check[Any]: return func - if inspect.iscoroutinefunction(predicate): + if discord.utils._iscoroutinefunction(predicate): decorator.predicate = predicate else: @@ -2444,7 +2444,7 @@ def is_nsfw() -> Check[Any]: return func - if inspect.iscoroutinefunction(predicate): + if discord.utils._iscoroutinefunction(predicate): decorator.predicate = predicate else: diff --git a/discord/ext/tasks/__init__.py b/discord/ext/tasks/__init__.py index ba11d6322..e3d9c33e7 100644 --- a/discord/ext/tasks/__init__.py +++ b/discord/ext/tasks/__init__.py @@ -46,7 +46,7 @@ import inspect from collections.abc import Sequence from discord.backoff import ExponentialBackoff -from discord.utils import MISSING +from discord.utils import MISSING, _iscoroutinefunction _log = logging.getLogger(__name__) @@ -182,7 +182,7 @@ class Loop(Generic[LF]): self._last_iteration: datetime.datetime = MISSING self._next_iteration = None - if not inspect.iscoroutinefunction(self.coro): + if not _iscoroutinefunction(self.coro): raise TypeError(f'Expected coroutine function, not {type(self.coro).__name__!r}.') async def _call_loop_function(self, name: str, *args: Any, **kwargs: Any) -> None: @@ -574,7 +574,7 @@ class Loop(Generic[LF]): The function was not a coroutine. """ - if not inspect.iscoroutinefunction(coro): + if not _iscoroutinefunction(coro): raise TypeError(f'Expected coroutine function, received {coro.__class__.__name__}.') self._before_loop = coro @@ -602,7 +602,7 @@ class Loop(Generic[LF]): The function was not a coroutine. """ - if not inspect.iscoroutinefunction(coro): + if not _iscoroutinefunction(coro): raise TypeError(f'Expected coroutine function, received {coro.__class__.__name__}.') self._after_loop = coro @@ -632,7 +632,7 @@ class Loop(Generic[LF]): TypeError The function was not a coroutine. """ - if not inspect.iscoroutinefunction(coro): + if not _iscoroutinefunction(coro): raise TypeError(f'Expected coroutine function, received {coro.__class__.__name__}.') self._error = coro # type: ignore diff --git a/discord/member.py b/discord/member.py index 59c181724..8f7342877 100644 --- a/discord/member.py +++ b/discord/member.py @@ -25,7 +25,6 @@ DEALINGS IN THE SOFTWARE. from __future__ import annotations import datetime -import inspect import itertools from operator import attrgetter from typing import Any, Awaitable, Callable, Collection, Dict, List, Optional, TYPE_CHECKING, Tuple, TypeVar, Union @@ -190,7 +189,7 @@ def flatten_user(cls: T) -> T: # probably a member function by now def generate_function(x): # We want sphinx to properly show coroutine functions as coroutines - if inspect.iscoroutinefunction(value): + if utils._iscoroutinefunction(value): async def general(self, *args, **kwargs): # type: ignore return await getattr(self._user, x)(*args, **kwargs) diff --git a/discord/ui/button.py b/discord/ui/button.py index 4c1e4cc89..a0d6258ff 100644 --- a/discord/ui/button.py +++ b/discord/ui/button.py @@ -26,7 +26,6 @@ from __future__ import annotations import copy from typing import Callable, Literal, Optional, TYPE_CHECKING, Tuple, TypeVar, Union -import inspect import os @@ -34,6 +33,7 @@ from .item import Item, ContainedItemCallbackType as ItemCallbackType, _ItemCall from ..enums import ButtonStyle, ComponentType from ..partial_emoji import PartialEmoji, _EmojiTag from ..components import Button as ButtonComponent +from ..utils import _iscoroutinefunction __all__ = ( 'Button', @@ -370,7 +370,7 @@ def button( """ def decorator(func: ItemCallbackType[S, Button[V]]) -> ItemCallbackType[S, Button[V]]: - if not inspect.iscoroutinefunction(func): + if not _iscoroutinefunction(func): raise TypeError('button function must be a coroutine function') func.__discord_ui_model_type__ = Button diff --git a/discord/ui/select.py b/discord/ui/select.py index baa1e4df8..735c0c34a 100644 --- a/discord/ui/select.py +++ b/discord/ui/select.py @@ -40,14 +40,13 @@ from typing import ( ) from contextvars import ContextVar import copy -import inspect import os from .item import Item, ContainedItemCallbackType as ItemCallbackType, _ItemCallback from ..enums import ChannelType, ComponentType, SelectDefaultValueType from ..partial_emoji import PartialEmoji from ..emoji import Emoji -from ..utils import MISSING, _human_join +from ..utils import MISSING, _human_join, _iscoroutinefunction from ..components import ( SelectOption, SelectMenu, @@ -1209,7 +1208,7 @@ def select( """ def decorator(func: ItemCallbackType[S, BaseSelectT]) -> ItemCallbackType[S, BaseSelectT]: - if not inspect.iscoroutinefunction(func): + if not _iscoroutinefunction(func): raise TypeError('select function must be a coroutine function') callback_cls = getattr(cls, '__origin__', cls) if not issubclass(callback_cls, BaseSelect): diff --git a/discord/utils.py b/discord/utils.py index ba7bdd3e1..b4738a2b3 100644 --- a/discord/utils.py +++ b/discord/utils.py @@ -26,6 +26,7 @@ from __future__ import annotations import array import asyncio +import inspect from textwrap import TextWrapper from typing import ( Any, @@ -1542,3 +1543,11 @@ class _RawReprMixin: def __repr__(self) -> str: value = ' '.join(f'{attr}={getattr(self, attr)!r}' for attr in self.__slots__) return f'<{self.__class__.__name__} {value}>' + + +# `inspect.iscoroutinefunction()` only became equivalent to (now deprecated) `inspect.iscoroutinefunction()` in Python 3.12 +# https://github.com/python/cpython/issues/122858#issuecomment-2466239748 +if sys.version_info >= (3, 12): + _iscoroutinefunction = inspect.iscoroutinefunction +else: + _iscoroutinefunction = asyncio.iscoroutinefunction From 23e2c4d8deff2dd7ae00a1240b5c26590f55a38f Mon Sep 17 00:00:00 2001 From: LegoFan9 <97139608+Lego-Fan9@users.noreply.github.com> Date: Tue, 14 Apr 2026 21:28:22 -0400 Subject: [PATCH 06/10] docs: fix: Safari sidebar ul has toolbar cut off --- docs/_static/style.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/_static/style.css b/docs/_static/style.css index 4354344ec..69728a807 100644 --- a/docs/_static/style.css +++ b/docs/_static/style.css @@ -387,7 +387,7 @@ aside { background-color: var(--mobile-nav-background); color: var(--mobile-nav-text); z-index: 2; - max-height: 100vh; + max-height: 100dvh; overflow-y: auto; overscroll-behavior-y: contain; } @@ -1285,7 +1285,7 @@ div.code-block-caption { display: inline-block; position: sticky; top: 1em; - max-height: calc(100vh - 2em); + max-height: calc(100dvh - 2em); max-width: 100%; overflow-y: auto; margin: 1em; From 84f9877860d434969443c68ad2bed5f66ac0270f Mon Sep 17 00:00:00 2001 From: Mikey Whiston Date: Wed, 15 Apr 2026 02:32:09 +0100 Subject: [PATCH 07/10] Fix comment about inspect replacing inspect --- discord/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discord/utils.py b/discord/utils.py index b4738a2b3..cb826d6d2 100644 --- a/discord/utils.py +++ b/discord/utils.py @@ -1545,7 +1545,7 @@ class _RawReprMixin: return f'<{self.__class__.__name__} {value}>' -# `inspect.iscoroutinefunction()` only became equivalent to (now deprecated) `inspect.iscoroutinefunction()` in Python 3.12 +# `inspect.iscoroutinefunction()` only became equivalent to (now deprecated) `asyncio.iscoroutinefunction()` in Python 3.12 # https://github.com/python/cpython/issues/122858#issuecomment-2466239748 if sys.version_info >= (3, 12): _iscoroutinefunction = inspect.iscoroutinefunction From d354614b10ac40c77d290f46aee488851db1b48c Mon Sep 17 00:00:00 2001 From: Michael Date: Thu, 21 May 2026 17:33:10 +0300 Subject: [PATCH 08/10] Fix safety_alerts_channel typing not accepting None in Guild.edit() --- discord/guild.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/discord/guild.py b/discord/guild.py index 0dd999de8..8fb4e6fa1 100644 --- a/discord/guild.py +++ b/discord/guild.py @@ -2027,7 +2027,7 @@ class Guild(Hashable): widget_channel: Optional[Snowflake] = MISSING, mfa_level: MFALevel = MISSING, raid_alerts_disabled: bool = MISSING, - safety_alerts_channel: TextChannel = MISSING, + safety_alerts_channel: Optional[TextChannel] = MISSING, invites_disabled_until: datetime.datetime = MISSING, dms_disabled_until: datetime.datetime = MISSING, ) -> Guild: @@ -2285,8 +2285,7 @@ class Guild(Hashable): raise TypeError( f'safety_alerts_channel must be of type TextChannel not {safety_alerts_channel.__class__.__name__}' ) - - fields['safety_alerts_channel_id'] = safety_alerts_channel.id + fields['safety_alerts_channel_id'] = safety_alerts_channel.id if owner is not MISSING: if self.owner_id != self._state.self_id: From 6161aa9561c7edb5cd238723e107b2369e4ab7ed Mon Sep 17 00:00:00 2001 From: Evanroby Date: Thu, 21 May 2026 16:34:20 +0200 Subject: [PATCH 09/10] Fix various typos within the documentation --- docs/api.rst | 4 ++-- docs/ext/commands/commands.rst | 6 +++--- docs/ext/commands/extensions.rst | 2 +- docs/intents.rst | 2 +- docs/interactions/api.rst | 8 ++++---- docs/version_guarantees.rst | 5 ++--- 6 files changed, 13 insertions(+), 14 deletions(-) diff --git a/docs/api.rst b/docs/api.rst index 5d816087e..5ed9ffb39 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -2846,7 +2846,7 @@ of :class:`enum.Enum`. .. attribute:: scheduled_event_update - A scheduled event was created. + A scheduled event was updated. When this is the action, the type of :attr:`~AuditLogEntry.target` is the :class:`ScheduledEvent` or :class:`Object` with the ID of the event @@ -2866,7 +2866,7 @@ of :class:`enum.Enum`. .. attribute:: scheduled_event_delete - A scheduled event was created. + A scheduled event was deleted. When this is the action, the type of :attr:`~AuditLogEntry.target` is the :class:`ScheduledEvent` or :class:`Object` with the ID of the event diff --git a/docs/ext/commands/commands.rst b/docs/ext/commands/commands.rst index c6ef75b30..a0f867c08 100644 --- a/docs/ext/commands/commands.rst +++ b/docs/ext/commands/commands.rst @@ -1212,7 +1212,7 @@ This allows you to define a command as both slash and text command without writi both counterparts. -In order to define a hybrid command, The command callback should be decorated with +In order to define a hybrid command, the command callback should be decorated with :meth:`.Bot.hybrid_command` decorator. .. code-block:: python3 @@ -1264,11 +1264,11 @@ Apart from that, all other features such as converters, checks, autocomplete, fl are supported on hybrid commands. Note that due to a design constraint, decorators related to application commands such as :func:`discord.app_commands.autocomplete` should be placed below the :func:`~ext.commands.hybrid_command` decorator. -For convenience and ease in writing code, The :class:`~ext.commands.Context` class implements +For convenience and ease in writing code, the :class:`~ext.commands.Context` class implements some behavioural changes for various methods and attributes: - :attr:`.Context.interaction` can be used to retrieve the slash command interaction. -- Since interaction can only be responded to once, The :meth:`.Context.send` automatically +- Since interaction can only be responded to once, the :meth:`.Context.send` automatically determines whether to send an interaction response or a followup response. - :meth:`.Context.defer` defers the interaction response for slash commands but shows typing indicator for text commands. diff --git a/docs/ext/commands/extensions.rst b/docs/ext/commands/extensions.rst index d03607845..20514b1d4 100644 --- a/docs/ext/commands/extensions.rst +++ b/docs/ext/commands/extensions.rst @@ -10,7 +10,7 @@ There comes a time in the bot development when you want to extend the bot functi Primer -------- -An extension at its core is a python file with an entry point called ``setup``. This setup function must be a Python coroutine. It takes a single parameter -- the :class:`~.commands.Bot` that loads the extension. +An extension at its core is a Python file with an entry point called ``setup``. This setup function must be a Python coroutine. It takes a single parameter -- the :class:`~.commands.Bot` that loads the extension. An example extension looks like this: diff --git a/docs/intents.rst b/docs/intents.rst index ca85ab8dd..3dbaa7fb5 100644 --- a/docs/intents.rst +++ b/docs/intents.rst @@ -153,7 +153,7 @@ If the cache is disabled or you disable chunking guilds at startup, we might sti - :meth:`Guild.fetch_member` - Used to fetch a member by ID through the HTTP API. - :meth:`Guild.fetch_members` - - used to fetch a large number of members through the HTTP API. + - Used to fetch a large number of members through the HTTP API. It should be noted that the gateway has a strict rate limit of 120 requests per 60 seconds. diff --git a/docs/interactions/api.rst b/docs/interactions/api.rst index a7a015f3a..2e60e211d 100644 --- a/docs/interactions/api.rst +++ b/docs/interactions/api.rst @@ -533,10 +533,10 @@ Enumerations .. attribute:: file_upload - Represents a file upload component, usually in a modal. + Represents a file upload component, usually in a modal. + + .. versionadded:: 2.7 - .. versionadded:: 2.7 - .. attribute:: radio_group Represents a radio group component. @@ -634,7 +634,7 @@ Enumerations A string parameter. .. attribute:: integer - A integer parameter. + An integer parameter. .. attribute:: boolean A boolean parameter. diff --git a/docs/version_guarantees.rst b/docs/version_guarantees.rst index c3d86749f..c5e73c5f2 100644 --- a/docs/version_guarantees.rst +++ b/docs/version_guarantees.rst @@ -24,9 +24,8 @@ Examples of Non-Breaking Changes - Adding or removing private underscored attributes. - Adding an element into the ``__slots__`` of a data class. - Changing the behaviour of a function to fix a bug. -- Changes in the typing behaviour of the library -- Changes in the calling convention of functions that are primarily meant as callbacks +- Changes in the typing behaviour of the library. +- Changes in the calling convention of functions that are primarily meant as callbacks. - Changes in the documentation. - Modifying the internal HTTP handling. - Upgrading the dependencies to a new version, major or otherwise. - From 2fbed9362422dad4f7850eb6c5d9b1f8bff7c71a Mon Sep 17 00:00:00 2001 From: Oliver Ni Date: Thu, 21 May 2026 07:34:48 -0700 Subject: [PATCH 10/10] Fix CRLF line endings in test_permissions_all.py --- tests/test_permissions_all.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/test_permissions_all.py b/tests/test_permissions_all.py index 883dc1b63..d9343a835 100644 --- a/tests/test_permissions_all.py +++ b/tests/test_permissions_all.py @@ -1,7 +1,7 @@ -import discord - -from functools import reduce -from operator import or_ - -def test_permissions_all(): - assert discord.Permissions.all().value == reduce(or_, discord.Permissions.VALID_FLAGS.values()) +import discord + +from functools import reduce +from operator import or_ + +def test_permissions_all(): + assert discord.Permissions.all().value == reduce(or_, discord.Permissions.VALID_FLAGS.values())