Skip to content

Commit 7e01223

Browse files
authored
Merge pull request #1665 from interactions-py/unstable
5.12.0
2 parents 1a7de56 + 92044a8 commit 7e01223

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+3929
-250
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@ __pycache__
1818
/coverage.xml
1919
/TestResults.xml
2020
/.coverage
21+
.mypy_cache/

.pre-commit-config.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,12 @@ repos:
3030
- id: check-merge-conflict
3131
name: Merge Conflicts
3232
- repo: https://github.com/astral-sh/ruff-pre-commit
33-
rev: 'v0.1.5'
33+
rev: 'v0.3.2'
3434
hooks:
3535
- id: ruff
3636
args: [--fix, --exit-non-zero-on-fix]
3737
- repo: https://github.com/psf/black
38-
rev: 23.11.0
38+
rev: 24.2.0
3939
hooks:
4040
- id: black
4141
name: Black Formatting

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
[![](https://img.shields.io/pypi/dm/discord-py-slash-command.svg?logo=python&label=Downloads)](https://pypi.org/project/discord-py-interactions/)
99

1010
[![](https://img.shields.io/badge/Code%20Style-black-000000.svg)](https://github.com/psf/black)
11-
[![License](https://img.shields.io/badge/License-GPL-blue)](https://github.com/interactions-py/interactions.py/blob/stable/LICENSE)
11+
[![License](https://img.shields.io/badge/License-MIT-blue)](https://github.com/interactions-py/interactions.py/blob/stable/LICENSE)
1212

1313
[![](https://img.shields.io/badge/Docs-latest-x?logo=readthedocs)](https://interactions-py.github.io/interactions.py/)
1414
[![](https://img.shields.io/badge/Guides-latest-x?logo=readthedocs)](https://interactions-py.github.io/interactions.py/Guides/01%20Getting%20Started)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
::: interactions.models.discord.entitlement

docs/src/API Reference/API Reference/models/Discord/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ search:
1414
- [Components](components)
1515
- [Embed](embed)
1616
- [Emoji](emoji)
17+
- [Entitlement](entitlement)
1718
- [Enums](enums)
1819
- [File](file)
1920
- [Guild](guild)

docs/src/Guides/03 Creating Commands.md

Lines changed: 103 additions & 50 deletions
Large diffs are not rendered by default.

docs/src/Guides/05 Components.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ When responding to a component you need to satisfy Discord either by responding
193193

194194
You can also use this to check for a normal message instead of a component interaction.
195195

196-
For more information, please visit the API reference [here](/interactions.py/API Reference/API Reference/client/#interactions.client.client.Client.wait_for_component).
196+
For more information, please visit the API reference [here](/interactions.py/API Reference/API Reference/Client/#interactions.client.Client.wait_for_component).
197197

198198

199199
=== ":two: Persistent Callback: `@listen()`"

docs/src/Guides/25 Error Tracking.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ And this is great when debugging. But it consumes your rate limit, can run into
3636

3737
interactions.py contains built-in support for Sentry.io, a cloud error tracking platform.
3838

39-
To enable it, call `bot.load_extension('interactions.ext.sentry', token=SENTRY_TOKEN)` as early as possible in your startup. (Load it before your own extensions, so it can catch intitialization errors in those extensions)
39+
To enable it, call `bot.load_extension('interactions.ext.sentry', dsn=SENTRY_DSN)` as early as possible in your startup. Load this extension before your own extensions, so it can catch intitialization errors in those extensions. `SENTRY_DSN` is provided by your Sentry.io project and should look something like `https://...@o9253.sentry.io/1048576`.
4040

4141
# What does this do that vanilla Sentry doesn't?
4242

interactions/__init__.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,7 @@
129129
EmbedField,
130130
EmbedFooter,
131131
EmbedProvider,
132+
Entitlement,
132133
ExplicitContentFilterLevel,
133134
Extension,
134135
File,
@@ -223,6 +224,11 @@
223224
NoArgumentConverter,
224225
NSFWLevel,
225226
open_file,
227+
Onboarding,
228+
OnboardingMode,
229+
OnboardingPrompt,
230+
OnboardingPromptOption,
231+
OnboardingPromptType,
226232
OptionType,
227233
OrTrigger,
228234
OverwriteType,
@@ -455,6 +461,7 @@
455461
"EmbedField",
456462
"EmbedFooter",
457463
"EmbedProvider",
464+
"Entitlement",
458465
"errors",
459466
"events",
460467
"ExplicitContentFilterLevel",
@@ -562,6 +569,11 @@
562569
"NoArgumentConverter",
563570
"NSFWLevel",
564571
"open_file",
572+
"Onboarding",
573+
"OnboardingMode",
574+
"OnboardingPrompt",
575+
"OnboardingPromptOption",
576+
"OnboardingPromptType",
565577
"OptionType",
566578
"OrTrigger",
567579
"OverwriteType",

interactions/api/events/__init__.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@
1212
ChannelDelete,
1313
ChannelPinsUpdate,
1414
ChannelUpdate,
15+
EntitlementCreate,
16+
EntitlementDelete,
17+
EntitlementUpdate,
1518
GuildAuditLogEntryCreate,
1619
GuildAvailable,
1720
GuildEmojisUpdate,
@@ -41,6 +44,7 @@
4144
MessageReactionAdd,
4245
MessageReactionRemove,
4346
MessageReactionRemoveAll,
47+
MessageReactionRemoveEmoji,
4448
MessageUpdate,
4549
NewThreadCreate,
4650
PresenceUpdate,
@@ -120,6 +124,9 @@
120124
"ComponentError",
121125
"Connect",
122126
"Disconnect",
127+
"EntitlementCreate",
128+
"EntitlementDelete",
129+
"EntitlementUpdate",
123130
"Error",
124131
"ExtensionCommandParse",
125132
"ExtensionLoad",
@@ -155,6 +162,7 @@
155162
"MessageReactionAdd",
156163
"MessageReactionRemove",
157164
"MessageReactionRemoveAll",
165+
"MessageReactionRemoveEmoji",
158166
"MessageUpdate",
159167
"ModalCompletion",
160168
"ModalError",

interactions/api/events/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ async def some_func(self, event):
5959
```
6060
Returns:
6161
A listener object.
62+
6263
"""
6364
listener = models.Listener.create(cls().resolved_name)(coro)
6465
client.add_listener(listener)

interactions/api/events/discord.py

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ async def an_event_handler(event: ChannelCreate):
4343
"ChannelDelete",
4444
"ChannelPinsUpdate",
4545
"ChannelUpdate",
46+
"EntitlementCreate",
47+
"EntitlementDelete",
48+
"EntitlementUpdate",
4649
"GuildAuditLogEntryCreate",
4750
"GuildEmojisUpdate",
4851
"GuildJoin",
@@ -72,6 +75,7 @@ async def an_event_handler(event: ChannelCreate):
7275
"MessageReactionAdd",
7376
"MessageReactionRemove",
7477
"MessageReactionRemoveAll",
78+
"MessageReactionRemoveEmoji",
7579
"MessageUpdate",
7680
"NewThreadCreate",
7781
"PresenceUpdate",
@@ -108,6 +112,7 @@ async def an_event_handler(event: ChannelCreate):
108112
VoiceChannel,
109113
)
110114
from interactions.models.discord.emoji import CustomEmoji, PartialEmoji
115+
from interactions.models.discord.entitlement import Entitlement
111116
from interactions.models.discord.guild import Guild, GuildIntegration
112117
from interactions.models.discord.message import Message
113118
from interactions.models.discord.reaction import Reaction
@@ -573,6 +578,16 @@ class MessageReactionRemoveAll(GuildEvent):
573578
"""The message that was reacted to"""
574579

575580

581+
@attrs.define(eq=False, order=False, hash=False, kw_only=False)
582+
class MessageReactionRemoveEmoji(MessageReactionRemoveAll):
583+
"""Dispatched when all reactions of a specifc emoji are removed from a message."""
584+
585+
emoji: "PartialEmoji" = attrs.field(
586+
repr=False,
587+
)
588+
"""The emoji that was removed"""
589+
590+
576591
@attrs.define(eq=False, order=False, hash=False, kw_only=False)
577592
class PresenceUpdate(BaseEvent):
578593
"""A user's presence has changed."""
@@ -821,3 +836,28 @@ def member(self) -> Optional["Member"]:
821836
@attrs.define(eq=False, order=False, hash=False, kw_only=False)
822837
class GuildScheduledEventUserRemove(GuildScheduledEventUserAdd):
823838
"""Dispatched when scheduled event is removed"""
839+
840+
841+
@attrs.define(eq=False, order=False, hash=False, kw_only=False)
842+
class BaseEntitlementEvent(BaseEvent):
843+
entitlement: "Entitlement" = attrs.field(repr=True)
844+
845+
846+
@attrs.define(eq=False, order=False, hash=False, kw_only=False)
847+
class EntitlementCreate(BaseEntitlementEvent):
848+
"""Dispatched when a user subscribes to a SKU."""
849+
850+
851+
@attrs.define(eq=False, order=False, hash=False, kw_only=False)
852+
class EntitlementUpdate(BaseEntitlementEvent):
853+
"""Dispatched when a user's subscription renews for the next billing period."""
854+
855+
856+
@attrs.define(eq=False, order=False, hash=False, kw_only=False)
857+
class EntitlementDelete(BaseEntitlementEvent):
858+
"""
859+
Dispatched when a user's entitlement is deleted.
860+
861+
Notably, this event is not dispatched when a user's subscription is cancelled.
862+
Instead, you simply won't receive an EntitlementUpdate event for the next billing period.
863+
"""

interactions/api/events/internal.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ async def an_event_handler(event: ChannelCreate):
1919
While all of these events are documented, not all of them are used, currently.
2020
2121
"""
22+
2223
import re
2324
import typing
2425
from typing import Any, Optional, TYPE_CHECKING, Type

interactions/api/events/processors/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from .voice_events import VoiceEvents
1313
from ._template import Processor
1414
from .auto_mod import AutoModEvents
15+
from .entitlement_events import EntitlementEvents
1516

1617
__all__ = (
1718
"ChannelEvents",
@@ -28,4 +29,5 @@
2829
"VoiceEvents",
2930
"Processor",
3031
"AutoModEvents",
32+
"EntitlementEvents",
3133
)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
from typing import TYPE_CHECKING
2+
3+
from interactions.models.discord.entitlement import Entitlement
4+
import interactions.api.events as events
5+
from ._template import EventMixinTemplate, Processor
6+
7+
if TYPE_CHECKING:
8+
from interactions.api.events import RawGatewayEvent
9+
10+
11+
class EntitlementEvents(EventMixinTemplate):
12+
@Processor.define()
13+
async def _on_raw_entitlement_create(self, event: "RawGatewayEvent") -> None:
14+
self.dispatch(events.EntitlementCreate(Entitlement.from_dict(event.data, self)))
15+
16+
@Processor.define()
17+
async def _on_raw_entitlement_update(self, event: "RawGatewayEvent") -> None:
18+
self.dispatch(events.EntitlementUpdate(Entitlement.from_dict(event.data, self)))
19+
20+
@Processor.define()
21+
async def _on_raw_entitlement_delete(self, event: "RawGatewayEvent") -> None:
22+
self.dispatch(events.EntitlementDelete(Entitlement.from_dict(event.data, self)))

interactions/api/events/processors/reaction_events.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,24 @@ async def _on_raw_message_reaction_remove_all(self, event: "RawGatewayEvent") ->
8181
await self.cache.fetch_message(event.data["channel_id"], event.data["message_id"]),
8282
)
8383
)
84+
85+
@Processor.define()
86+
async def _on_raw_message_reaction_remove_emoji(self, event: "RawGatewayEvent") -> None:
87+
emoji = PartialEmoji.from_dict(event.data.get("emoji"))
88+
message = self.cache.get_message(event.data.get("channel_id"), event.data.get("message_id"))
89+
90+
if message:
91+
for i, reaction in enumerate(message.reactions):
92+
if reaction.emoji == emoji:
93+
message.reactions.pop(i)
94+
break
95+
else:
96+
message = await self.cache.fetch_message(event.data.get("channel_id"), event.data.get("message_id"))
97+
98+
self.dispatch(
99+
events.MessageReactionRemoveEmoji(
100+
event.data.get("guild_id"),
101+
message,
102+
emoji,
103+
)
104+
)

interactions/api/gateway/gateway.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
"""Outlines the interaction between interactions and Discord's Gateway API."""
2+
23
import asyncio
34
import logging
45
import sys
@@ -161,7 +162,7 @@ async def run(self) -> None:
161162
self.sequence = seq
162163

163164
if op == OPCODE.DISPATCH:
164-
_ = asyncio.create_task(self.dispatch_event(data, seq, event))
165+
_ = asyncio.create_task(self.dispatch_event(data, seq, event)) # noqa: RUF006
165166
continue
166167

167168
# This may try to reconnect the connection so it is best to wait
@@ -214,6 +215,7 @@ async def dispatch_event(self, data, seq, event) -> None:
214215
return self.state.client.dispatch(events.WebsocketReady(data))
215216

216217
case "RESUMED":
218+
self.state._shard_ready.set()
217219
self.state.wrapped_logger(
218220
logging.INFO, f"Successfully resumed connection! Session_ID: {self.session_id}"
219221
)
@@ -228,7 +230,7 @@ async def dispatch_event(self, data, seq, event) -> None:
228230
event_name = f"raw_{event.lower()}"
229231
if processor := self.state.client.processors.get(event_name):
230232
try:
231-
_ = asyncio.create_task(
233+
_ = asyncio.create_task( # noqa: RUF006
232234
processor(events.RawGatewayEvent(data.copy(), override_name=event_name))
233235
)
234236
except Exception as ex:

interactions/api/gateway/state.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ def wrapped_logger(self, level: int, message: str, **kwargs) -> None:
138138
level: The logging level
139139
message: The message to log
140140
**kwargs: Any additional keyword arguments that Logger.log accepts
141+
141142
"""
142143
self.logger.log(level, f"Shard ID {self.shard_id} | {message}", **kwargs)
143144

@@ -178,6 +179,7 @@ async def change_presence(
178179
ActivityType.LISTENING,
179180
ActivityType.WATCHING,
180181
ActivityType.COMPETING,
182+
ActivityType.CUSTOM,
181183
]:
182184
self.wrapped_logger(
183185
logging.WARNING, f"Activity type `{ActivityType(activity.type).name}` may not be enabled for bots"

interactions/api/gateway/websocket.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -315,12 +315,10 @@ async def _start_bee_gees(self) -> None:
315315
return
316316

317317
@abstractmethod
318-
async def _identify(self) -> None:
319-
...
318+
async def _identify(self) -> None: ...
320319

321320
@abstractmethod
322-
async def _resume_connection(self) -> None:
323-
...
321+
async def _resume_connection(self) -> None: ...
324322

325323
@abstractmethod
326324
async def send_heartbeat(self) -> None:

0 commit comments

Comments
 (0)