Skip to content

Commit e949202

Browse files
authored
Merge: 5.6.0
5.6.0
2 parents a101b8e + 63369e8 commit e949202

File tree

22 files changed

+180
-27
lines changed

22 files changed

+180
-27
lines changed

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ repos:
3030
- id: check-merge-conflict
3131
name: Merge Conflicts
3232
- repo: https://github.com/charliermarsh/ruff-pre-commit
33-
rev: 'v0.0.261'
33+
rev: 'v0.0.270'
3434
hooks:
3535
- id: ruff
3636
args: [--fix, --exit-non-zero-on-fix]

docs/src/Guides/25 Error Tracking.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@ So, you've finally got your bot running on a server somewhere. Chances are, you
44

55
You're going to want to have some way of tracking if errors occur.
66

7+
# Sending inline tracebacks
8+
9+
By default, if a command throws an uncaught exception, it'll send the traceback to the user. This is very useful when in development, but doesn't help you once you've gone public, and might not be in the same servers as your errors. Non-technical users may also find it confusing to see trackbacks instead of user-friendly error messages.
10+
11+
If you wish to turn this off, create your client with `Client(..., send_command_tracebacks=False)`
12+
13+
714
# The simple and dirty method
815

916
!!! Please don't actually do this.

examples/bot.py

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# This code shows a very brief and small example of how to create a bot with our library.
22
# This example does not cover all the features of the library, but it is enough to get you started.
33
# In order to learn more about how to use the library, please head over to our documentation:
4-
# https://interactionspy.readthedocs.io/en/latest/
4+
# https://interactions-py.github.io/interactions.py/
55

66
# The first thing you need to do is import the library.
77
import interactions
@@ -10,7 +10,11 @@
1010
# When you make a bot, we refer to it as the "client."
1111
# The client is the main object that interacts with the Gateway, what talks to Discord.
1212
# The client is also the main object that interacts with the API, what makes requests with Discord.
13-
client = interactions.Client()
13+
# The client can also have "intents" that are what the bot recieves,
14+
# in this case the default ones and message content (a privilaged intent that needs
15+
# to be enabled in the developer portal)
16+
intents = interactions.Intents.DEFAULT | interactions.Intents.MESSAGE_CONTENT
17+
client = interactions.Client(intents=intents)
1418

1519

1620
# With our client established, let's have the library inform us when the client is ready.
@@ -25,18 +29,21 @@ async def on_ready():
2529
print(f"Our latency is {round(client.latency)} ms.")
2630

2731

32+
# We can either pass in the event name or make the function name be the event name.
2833
@interactions.listen("on_message_create")
29-
async def name_this_however_you_want(message: interactions.Message):
34+
async def name_this_however_you_want(message_create: interactions.events.MessageCreate):
3035
# Whenever we specify any other event type that isn't "READY," the function underneath
3136
# the decorator will most likely have an argument required. This argument is the data
3237
# that is being supplied back to us developers, which we call a data model.
3338

3439
# In this example, we're listening to messages being created. This means we can expect
35-
# a "message" argument to be passed to the function, which will be the data model of such.
40+
# a "message_create" argument to be passed to the function, which will contain the
41+
# data model for the message
3642

3743
# We can use the data model to access the data we need.
3844
# Keep in mind that you can only access the message content if your bot has the MESSAGE_CONTENT intent.
3945
# You can find more information on this in the migration section of the quickstart guide.
46+
message: interactions.Message = message_create.message
4047
print(f"We've received a message from {message.author.username}. The message is: {message.content}.")
4148

4249

@@ -66,5 +73,6 @@ async def hello_world(ctx: interactions.SlashContext):
6673
# object on line 13.
6774
# - we are not setting a presence.
6875
# - we are not automatically sharding, and registering the connection under 1 shard.
69-
# - we are using default intents, which are Gateway intents excluding privileged ones.
76+
# - we are using default intents, which are Gateway intents excluding privileged ones
77+
# - and the privilaged message content intent.
7078
client.start("Your token here.")

interactions/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@
113113
CustomEmojiConverter,
114114
DateTrigger,
115115
DefaultNotificationLevel,
116+
DefaultReaction,
116117
DM,
117118
dm_only,
118119
DMChannel,
@@ -233,12 +234,14 @@
233234
process_color,
234235
process_colour,
235236
process_components,
237+
process_default_reaction,
236238
process_embeds,
237239
process_emoji,
238240
process_emoji_req_format,
239241
process_message_payload,
240242
process_message_reference,
241243
process_permission_overwrites,
244+
process_thread_tag,
242245
Reaction,
243246
ReactionUsers,
244247
Resolved,
@@ -425,6 +428,7 @@
425428
"CustomEmojiConverter",
426429
"DateTrigger",
427430
"DefaultNotificationLevel",
431+
"DefaultReaction",
428432
"DISCORD_EPOCH",
429433
"DM",
430434
"dm_only",
@@ -564,12 +568,14 @@
564568
"process_color",
565569
"process_colour",
566570
"process_components",
571+
"process_default_reaction",
567572
"process_embeds",
568573
"process_emoji",
569574
"process_emoji_req_format",
570575
"process_message_payload",
571576
"process_message_reference",
572577
"process_permission_overwrites",
578+
"process_thread_tag",
573579
"Reaction",
574580
"ReactionUsers",
575581
"Resolved",

interactions/api/events/discord.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ def on_guild_join(event):
2929
from interactions.api.events.base import GuildEvent, BaseEvent
3030
from interactions.client.const import Absent
3131
from interactions.client.utils.attr_utils import docs
32+
from interactions.models.discord.snowflake import to_snowflake
3233

3334
__all__ = (
3435
"ApplicationCommandPermissionsUpdate",
@@ -292,6 +293,9 @@ class GuildUpdate(BaseEvent):
292293
class GuildLeft(BaseEvent):
293294
"""Dispatched when a guild is left."""
294295

296+
guild_id: "Snowflake_Type" = attrs.field(repr=True, converter=to_snowflake)
297+
"""The ID of the guild"""
298+
295299
guild: "Guild" = attrs.field(repr=True)
296300
"""The guild this event is dispatched from"""
297301

interactions/api/events/processors/guild_events.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ async def _on_raw_guild_delete(self, event: "RawGatewayEvent") -> None:
6969
guild = self.cache.get_guild(guild_id)
7070
self.cache.delete_guild(guild_id)
7171

72-
self.dispatch(events.GuildLeft(guild))
72+
self.dispatch(events.GuildLeft(guild_id, guild))
7373

7474
@Processor.define()
7575
async def _on_raw_guild_ban_add(self, event: "RawGatewayEvent") -> None:

interactions/api/http/http_requests/members.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ async def modify_guild_member(
8080
roles: list["Snowflake_Type"] | None = None,
8181
mute: bool | None = None,
8282
deaf: bool | None = None,
83-
channel_id: "Snowflake_Type | None" = None,
83+
channel_id: "Snowflake_Type | MISSING" = MISSING,
8484
communication_disabled_until: str | datetime | Timestamp | None | Missing = MISSING,
8585
reason: str | None = None,
8686
) -> discord_typings.GuildMemberData:
@@ -109,9 +109,10 @@ async def modify_guild_member(
109109
"roles": roles,
110110
"mute": mute,
111111
"deaf": deaf,
112-
"channel_id": int(channel_id) if channel_id else None,
113112
}
114113
payload = dict_filter_none(payload)
114+
if channel_id is not MISSING:
115+
payload["channel_id"] = channel_id
115116

116117
if not isinstance(nickname, Missing):
117118
payload["nick"] = nickname

interactions/api/voice/voice_gateway.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,8 @@ def _udp_keep_alive(self) -> None:
280280
except socket.error as e:
281281
self.logger.warning(f"Ending Keep Alive due to {e}")
282282
return
283+
except AttributeError:
284+
return
283285
except Exception as e:
284286
self.logger.debug("Keep Alive Error: ", exc_info=e)
285287
self.logger.debug("Ending UDP Keep Alive")

interactions/client/client.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1801,7 +1801,7 @@ async def _dispatch_interaction(self, event: RawGatewayEvent) -> None: # noqa:
18011801
elif autocomplete := self._global_autocompletes.get(str(auto_opt.name)):
18021802
callback = autocomplete
18031803
else:
1804-
raise ValueError(f"Autocomplete callback for {str(auto_opt.name)} not found")
1804+
raise ValueError(f"Autocomplete callback for {auto_opt.name!s} not found")
18051805

18061806
await self.__dispatch_interaction(
18071807
ctx=ctx,

interactions/ext/debug_extension/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def _make_data_line(
112112
if isinstance(aligns, str):
113113
aligns = [aligns for _ in column_widths]
114114

115-
line = (f"{str(value): {align}{width}}" for width, align, value in zip(column_widths, aligns, line, strict=False))
115+
line = (f"{value!s: {align}{width}}" for width, align, value in zip(column_widths, aligns, line, strict=False))
116116
return f"{left_char}{f'{middle_char}'.join(line)}{right_char}"
117117

118118

interactions/ext/prefixed_commands/command.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -253,7 +253,7 @@ def _greedy_parse(greedy: Greedy, param: inspect.Parameter) -> Any:
253253
args = typing.get_args(arg)
254254

255255
if len(args) > 2 or NoneType not in args:
256-
raise ValueError(f"Greedy[{repr(arg)}] is invalid.")
256+
raise ValueError(f"Greedy[{arg!r}] is invalid.")
257257

258258
arg = args[0]
259259
default = None
@@ -317,7 +317,7 @@ async def _greedy_convert(
317317
if param.default:
318318
greedy_args = param.default # im sorry, typehinters
319319
else:
320-
raise BadArgument(f"Failed to find any arguments for {repr(param.type)}.")
320+
raise BadArgument(f"Failed to find any arguments for {param.type!r}.")
321321

322322
return greedy_args, broke_off
323323

interactions/ext/sentry.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,12 +91,13 @@ def setup(
9191
bot: Client,
9292
token: str = None,
9393
filter: Optional[Callable[[dict[str, Any], dict[str, Any]], Optional[dict[str, Any]]]] = None,
94+
**kwargs,
9495
) -> None:
9596
if not token:
9697
bot.logger.error("Cannot enable sentry integration, no token provided")
9798
return
9899
if filter is None:
99100
filter = default_sentry_filter
100-
sentry_sdk.init(token, before_send=filter)
101+
sentry_sdk.init(token, before_send=filter, **kwargs)
101102
Task.on_error_sentry_hook = HookedTask.on_error_sentry_hook # type: ignore
102103
SentryExtension(bot)

interactions/models/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
ComponentType,
4545
CustomEmoji,
4646
DefaultNotificationLevel,
47+
DefaultReaction,
4748
DM,
4849
DMChannel,
4950
DMGroup,
@@ -117,12 +118,14 @@
117118
process_color,
118119
process_colour,
119120
process_components,
121+
process_default_reaction,
120122
process_embeds,
121123
process_emoji,
122124
process_emoji_req_format,
123125
process_message_payload,
124126
process_message_reference,
125127
process_permission_overwrites,
128+
process_thread_tag,
126129
Reaction,
127130
ReactionUsers,
128131
Role,
@@ -373,6 +376,7 @@
373376
"CustomEmojiConverter",
374377
"DateTrigger",
375378
"DefaultNotificationLevel",
379+
"DefaultReaction",
376380
"DM",
377381
"dm_only",
378382
"DMChannel",
@@ -493,12 +497,14 @@
493497
"process_color",
494498
"process_colour",
495499
"process_components",
500+
"process_default_reaction",
496501
"process_embeds",
497502
"process_emoji",
498503
"process_emoji_req_format",
499504
"process_message_payload",
500505
"process_message_reference",
501506
"process_permission_overwrites",
507+
"process_thread_tag",
502508
"Reaction",
503509
"ReactionUsers",
504510
"Resolved",

interactions/models/discord/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@
160160
from .stage_instance import StageInstance
161161
from .sticker import Sticker, StickerItem, StickerPack
162162
from .team import Team, TeamMember
163-
from .thread import ThreadList, ThreadMember, ThreadTag
163+
from .thread import ThreadList, ThreadMember, ThreadTag, DefaultReaction, process_thread_tag, process_default_reaction
164164
from .timestamp import Timestamp, TimestampStyles
165165
from .user import BaseUser, Member, User, ClientUser
166166
from .voice_state import VoiceRegion, VoiceState
@@ -211,6 +211,7 @@
211211
"ComponentType",
212212
"CustomEmoji",
213213
"DefaultNotificationLevel",
214+
"DefaultReaction",
214215
"DM",
215216
"DMChannel",
216217
"DMGroup",
@@ -284,12 +285,14 @@
284285
"process_color",
285286
"process_colour",
286287
"process_components",
288+
"process_default_reaction",
287289
"process_embeds",
288290
"process_emoji",
289291
"process_emoji_req_format",
290292
"process_message_payload",
291293
"process_message_reference",
292294
"process_permission_overwrites",
295+
"process_thread_tag",
293296
"Reaction",
294297
"ReactionUsers",
295298
"Role",

interactions/models/discord/channel.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
to_optional_snowflake,
2424
SnowflakeObject,
2525
)
26-
from interactions.models.discord.thread import ThreadTag
26+
from interactions.models.discord.thread import DefaultReaction, ThreadTag
2727
from interactions.models.misc.context_manager import Typing
2828
from interactions.models.misc.iterator import AsyncIterator
2929
from .enums import (
@@ -348,8 +348,9 @@ async def fetch_messages(
348348
messages_data = await self._client.http.get_channel_messages(
349349
self.id, limit, around=around, before=before, after=after
350350
)
351-
for m in messages_data:
352-
m["guild_id"] = self._guild_id
351+
if isinstance(self, GuildChannel):
352+
for m in messages_data:
353+
m["guild_id"] = self._guild_id
353354

354355
return [self._client.cache.place_message_data(m) for m in messages_data]
355356

@@ -2387,6 +2388,8 @@ async def close_stage(self, reason: Absent[Optional[str]] = MISSING) -> None:
23872388
class GuildForum(GuildChannel):
23882389
available_tags: List[ThreadTag] = attrs.field(repr=False, factory=list)
23892390
"""A list of tags available to assign to threads"""
2391+
default_reaction_emoji: Optional[DefaultReaction] = attrs.field(repr=False, default=None)
2392+
"""The default emoji to react with for posts"""
23902393
last_message_id: Optional[Snowflake_Type] = attrs.field(repr=False, default=None)
23912394
# TODO: Implement "template" once the API supports them
23922395

interactions/models/discord/emoji.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
from interactions.client.utils.attr_converters import optional
1212
from interactions.client.utils.serializer import dict_filter_none, no_export_meta
1313
from interactions.models.discord.base import ClientObject
14-
from interactions.models.discord.snowflake import SnowflakeObject, to_snowflake
14+
from interactions.models.discord.snowflake import SnowflakeObject, to_snowflake, to_snowflake_list
1515

1616
if TYPE_CHECKING:
1717
from interactions.client import Client
@@ -185,7 +185,7 @@ async def edit(
185185
data_payload = dict_filter_none(
186186
{
187187
"name": name,
188-
"roles": roles,
188+
"roles": to_snowflake_list(roles) if roles else None,
189189
}
190190
)
191191

0 commit comments

Comments
 (0)