Skip to content

Commit 6f7964f

Browse files
authored
Merge branch 'master' into channel
2 parents 24108a9 + a5aa21f commit 6f7964f

36 files changed

+2743
-172
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ repos:
8787
args: [--prose-wrap=always, --print-width=88]
8888
exclude: \.(po|pot|yml|yaml)$
8989
- repo: https://github.com/DanielNoord/pydocstringformatter
90-
rev: v0.7.3
90+
rev: v0.7.5
9191
hooks:
9292
- id: pydocstringformatter
9393
exclude: \.(po|pot|yml|yaml)$

CHANGELOG.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,8 @@ These changes are available on the `master` branch, but have not yet been releas
154154

155155
### Removed
156156

157-
- Removed deprecated support for `Option` in `BridgeCommand`. Use `BridgeOption`
158-
instead. ([#2731])(https://github.com/Pycord-Development/pycord/pull/2731))
157+
- Removed deprecated support for `Option` in `BridgeCommand`, use `BridgeOption`
158+
instead. ([#2731](https://github.com/Pycord-Development/pycord/pull/2731))
159159

160160
## [2.6.1] - 2024-09-15
161161

discord/abc.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1615,6 +1615,12 @@ async def send(
16151615
)
16161616

16171617
components = view.to_components()
1618+
if view.is_components_v2():
1619+
if embeds or content:
1620+
raise TypeError(
1621+
"cannot send embeds or content with a view using v2 component logic"
1622+
)
1623+
flags.is_components_v2 = True
16181624
else:
16191625
components = None
16201626

@@ -1679,8 +1685,10 @@ async def send(
16791685

16801686
ret = state.create_message(channel=channel, data=data)
16811687
if view:
1682-
state.store_view(view, ret.id)
1688+
if view.is_dispatchable():
1689+
state.store_view(view, ret.id)
16831690
view.message = ret
1691+
view.refresh(ret.components)
16841692

16851693
if delete_after is not None:
16861694
await ret.delete(delay=delete_after)

discord/bot.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -884,15 +884,15 @@ async def process_application_commands(
884884

885885
ctx = await self.get_application_context(interaction)
886886
if command:
887-
ctx.command = command
887+
interaction.command = command
888888
await self.invoke_application_command(ctx)
889889

890890
async def on_application_command_auto_complete(
891891
self, interaction: Interaction, command: ApplicationCommand
892892
) -> None:
893893
async def callback() -> None:
894894
ctx = await self.get_autocomplete_context(interaction)
895-
ctx.command = command
895+
interaction.command = command
896896
return await command.invoke_autocomplete_callback(ctx)
897897

898898
autocomplete_task = self._bot.loop.create_task(callback())

discord/channel.py

Lines changed: 41 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,16 @@
2626
from __future__ import annotations
2727

2828
import datetime
29-
from typing import TYPE_CHECKING, Any, Callable, Iterable, Mapping, TypeVar, overload
29+
from typing import (
30+
TYPE_CHECKING,
31+
Any,
32+
Callable,
33+
Iterable,
34+
Mapping,
35+
Sequence,
36+
TypeVar,
37+
overload,
38+
)
3039

3140
import discord.abc
3241

@@ -45,7 +54,7 @@
4554
)
4655
from .errors import ClientException, InvalidArgument
4756
from .file import File
48-
from .flags import ChannelFlags
57+
from .flags import ChannelFlags, MessageFlags
4958
from .invite import Invite
5059
from .iterators import ArchivedThreadIterator
5160
from .mixins import Hashable
@@ -71,12 +80,15 @@
7180

7281
if TYPE_CHECKING:
7382
from .abc import Snowflake, SnowflakeTime
83+
from .embeds import Embed
7484
from .guild import Guild
7585
from .guild import GuildChannel as GuildChannelType
7686
from .member import Member, VoiceState
87+
from .mentions import AllowedMentions
7788
from .message import EmojiInputType, Message, PartialMessage
7889
from .role import Role
7990
from .state import ConnectionState
91+
from .sticker import GuildSticker, StickerItem
8092
from .types.channel import CategoryChannel as CategoryChannelPayload
8193
from .types.channel import DMChannel as DMChannelPayload
8294
from .types.channel import ForumChannel as ForumChannelPayload
@@ -87,6 +99,7 @@
8799
from .types.channel import VoiceChannel as VoiceChannelPayload
88100
from .types.snowflake import SnowflakeList
89101
from .types.threads import ThreadArchiveDuration
102+
from .ui.view import View
90103
from .user import BaseUser, ClientUser, User
91104
from .webhook import Webhook
92105

@@ -1183,18 +1196,20 @@ async def edit(self, *, reason=None, **options):
11831196
async def create_thread(
11841197
self,
11851198
name: str,
1186-
content=None,
1199+
content: str | None = None,
11871200
*,
1188-
embed=None,
1189-
embeds=None,
1190-
file=None,
1191-
files=None,
1192-
stickers=None,
1193-
delete_message_after=None,
1194-
nonce=None,
1195-
allowed_mentions=None,
1196-
view=None,
1197-
applied_tags=None,
1201+
embed: Embed | None = None,
1202+
embeds: list[Embed] | None = None,
1203+
file: File | None = None,
1204+
files: list[File] | None = None,
1205+
stickers: Sequence[GuildSticker | StickerItem] | None = None,
1206+
delete_message_after: float | None = None,
1207+
nonce: int | str | None = None,
1208+
allowed_mentions: AllowedMentions | None = None,
1209+
view: View | None = None,
1210+
applied_tags: list[ForumTag] | None = None,
1211+
suppress: bool = False,
1212+
silent: bool = False,
11981213
auto_archive_duration: ThreadArchiveDuration = MISSING,
11991214
slowmode_delay: int = MISSING,
12001215
reason: str | None = None,
@@ -1294,13 +1309,24 @@ async def create_thread(
12941309
else:
12951310
allowed_mentions = allowed_mentions.to_dict()
12961311

1312+
flags = MessageFlags(
1313+
suppress_embeds=bool(suppress),
1314+
suppress_notifications=bool(silent),
1315+
)
1316+
12971317
if view:
12981318
if not hasattr(view, "__discord_ui_view__"):
12991319
raise InvalidArgument(
13001320
f"view parameter must be View not {view.__class__!r}"
13011321
)
13021322

13031323
components = view.to_components()
1324+
if view.is_components_v2():
1325+
if embeds or content:
1326+
raise TypeError(
1327+
"cannot send embeds or content with a view using v2 component logic"
1328+
)
1329+
flags.is_components_v2 = True
13041330
else:
13051331
components = None
13061332

@@ -1339,6 +1365,7 @@ async def create_thread(
13391365
or self.default_auto_archive_duration,
13401366
rate_limit_per_user=slowmode_delay or self.slowmode_delay,
13411367
applied_tags=applied_tags,
1368+
flags=flags.value,
13421369
reason=reason,
13431370
)
13441371
finally:
@@ -1348,7 +1375,7 @@ async def create_thread(
13481375

13491376
ret = Thread(guild=self.guild, state=self._state, data=data)
13501377
msg = ret.get_partial_message(int(data["last_message_id"]))
1351-
if view:
1378+
if view and view.is_dispatchable():
13521379
state.store_view(view, msg.id)
13531380

13541381
if delete_message_after is not None:

discord/client.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,11 @@
6868
if TYPE_CHECKING:
6969
from .abc import GuildChannel, PrivateChannel, Snowflake, SnowflakeTime
7070
from .channel import DMChannel
71+
from .interaction import Interaction
7172
from .member import Member
7273
from .message import Message
7374
from .poll import Poll
75+
from .ui.item import Item
7476
from .voice_client import VoiceProtocol
7577

7678
__all__ = ("Client",)
@@ -541,6 +543,38 @@ async def on_error(self, event_method: str, *args: Any, **kwargs: Any) -> None:
541543
print(f"Ignoring exception in {event_method}", file=sys.stderr)
542544
traceback.print_exc()
543545

546+
async def on_view_error(
547+
self, error: Exception, item: Item, interaction: Interaction
548+
) -> None:
549+
"""|coro|
550+
551+
The default view error handler provided by the client.
552+
553+
This only fires for a view if you did not define its :func:`~discord.ui.View.on_error`.
554+
"""
555+
556+
print(
557+
f"Ignoring exception in view {interaction.view} for item {item}:",
558+
file=sys.stderr,
559+
)
560+
traceback.print_exception(
561+
error.__class__, error, error.__traceback__, file=sys.stderr
562+
)
563+
564+
async def on_modal_error(self, error: Exception, interaction: Interaction) -> None:
565+
"""|coro|
566+
567+
The default modal error handler provided by the client.
568+
The default implementation prints the traceback to stderr.
569+
570+
This only fires for a modal if you did not define its :func:`~discord.ui.Modal.on_error`.
571+
"""
572+
573+
print(f"Ignoring exception in modal {interaction.modal}:", file=sys.stderr)
574+
traceback.print_exception(
575+
error.__class__, error, error.__traceback__, file=sys.stderr
576+
)
577+
544578
# hooks
545579

546580
async def _call_before_identify_hook(

discord/commands/context.py

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -80,16 +80,13 @@ class ApplicationContext(discord.abc.Messageable):
8080
The bot that the command belongs to.
8181
interaction: :class:`.Interaction`
8282
The interaction object that invoked the command.
83-
command: :class:`.ApplicationCommand`
84-
The command that this context belongs to.
8583
"""
8684

8785
def __init__(self, bot: Bot, interaction: Interaction):
8886
self.bot = bot
8987
self.interaction = interaction
9088

9189
# below attributes will be set after initialization
92-
self.command: ApplicationCommand = None # type: ignore
9390
self.focused: Option = None # type: ignore
9491
self.value: str = None # type: ignore
9592
self.options: dict = None # type: ignore
@@ -136,6 +133,15 @@ async def invoke(
136133
"""
137134
return await command(self, *args, **kwargs)
138135

136+
@property
137+
def command(self) -> ApplicationCommand | None:
138+
"""The command that this context belongs to."""
139+
return self.interaction.command
140+
141+
@command.setter
142+
def command(self, value: ApplicationCommand | None) -> None:
143+
self.interaction.command = value
144+
139145
@cached_property
140146
def channel(self) -> InteractionChannel | None:
141147
"""Union[:class:`abc.GuildChannel`, :class:`PartialMessageable`, :class:`Thread`]:
@@ -393,8 +399,6 @@ class AutocompleteContext:
393399
The bot that the command belongs to.
394400
interaction: :class:`.Interaction`
395401
The interaction object that invoked the autocomplete.
396-
command: :class:`.ApplicationCommand`
397-
The command that this context belongs to.
398402
focused: :class:`.Option`
399403
The option the user is currently typing.
400404
value: :class:`.str`
@@ -403,13 +407,12 @@ class AutocompleteContext:
403407
A name to value mapping of the options that the user has selected before this option.
404408
"""
405409

406-
__slots__ = ("bot", "interaction", "command", "focused", "value", "options")
410+
__slots__ = ("bot", "interaction", "focused", "value", "options")
407411

408412
def __init__(self, bot: Bot, interaction: Interaction):
409413
self.bot = bot
410414
self.interaction = interaction
411415

412-
self.command: ApplicationCommand = None # type: ignore
413416
self.focused: Option = None # type: ignore
414417
self.value: str = None # type: ignore
415418
self.options: dict = None # type: ignore
@@ -423,3 +426,12 @@ def cog(self) -> Cog | None:
423426
return None
424427

425428
return self.command.cog
429+
430+
@property
431+
def command(self) -> ApplicationCommand | None:
432+
"""The command that this context belongs to."""
433+
return self.interaction.command
434+
435+
@command.setter
436+
def command(self, value: ApplicationCommand | None) -> None:
437+
self.interaction.command = value

0 commit comments

Comments
 (0)