Skip to content

Commit de41382

Browse files
authored
Merge branch 'master' into master
2 parents b86ae9f + dd37fff commit de41382

File tree

20 files changed

+630
-128
lines changed

20 files changed

+630
-128
lines changed

.github/workflows/bypass-review.yml

Lines changed: 0 additions & 31 deletions
This file was deleted.

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,5 @@ docs/crowdin.py
1515
*.flac
1616
*.mo
1717
.idea/
18+
.vs/slnx.sqlite
19+
env/

discord/bot.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545

4646
from .client import Client
4747
from .shard import AutoShardedClient
48-
from .utils import MISSING, get, async_all
48+
from .utils import MISSING, get, find, async_all
4949
from .commands import (
5050
SlashCommand,
5151
SlashCommandGroup,
@@ -59,6 +59,7 @@
5959

6060
from .errors import Forbidden, DiscordException
6161
from .interactions import Interaction
62+
from .enums import InteractionType
6263

6364
CoroFunc = Callable[..., Coroutine[Any, Any, Any]]
6465
CFT = TypeVar('CFT', bound=CoroFunc)
@@ -86,7 +87,7 @@ def pending_application_commands(self):
8687
return self._pending_application_commands
8788

8889
@property
89-
def commands(self) -> List[Union[ApplicationCommand, ...]]:
90+
def commands(self) -> List[Union[ApplicationCommand, Any]]:
9091
commands = list(self.application_commands.values())
9192
if self._supports_prefixed_commands:
9293
commands += self.prefixed_commands
@@ -188,7 +189,7 @@ async def register_commands(self) -> None:
188189
cmd = get(
189190
self.pending_application_commands,
190191
name=i["name"],
191-
description=i["description"],
192+
guild_ids=None,
192193
type=i["type"],
193194
)
194195
self.application_commands[i["id"]] = cmd
@@ -224,12 +225,7 @@ async def register_commands(self) -> None:
224225
raise
225226
else:
226227
for i in cmds:
227-
cmd = get(
228-
self.pending_application_commands,
229-
name=i["name"],
230-
description=i["description"],
231-
type=i["type"],
232-
)
228+
cmd = find(lambda cmd: cmd.name == i["name"] and cmd.type == i["type"] and int(i["guild_id"]) in cmd.guild_ids, self.pending_application_commands)
233229
self.application_commands[i["id"]] = cmd
234230

235231
# Permissions
@@ -364,14 +360,20 @@ async def process_application_commands(self, interaction: Interaction) -> None:
364360
interaction: :class:`discord.Interaction`
365361
The interaction to process
366362
"""
367-
if not interaction.is_command():
363+
if interaction.type not in (
364+
InteractionType.application_command,
365+
InteractionType.auto_complete
366+
):
368367
return
369368

370369
try:
371370
command = self.application_commands[interaction.data["id"]]
372371
except KeyError:
373372
self.dispatch("unknown_command", interaction)
374373
else:
374+
if interaction.type is InteractionType.auto_complete:
375+
return await command.invoke_autocomplete_callback(interaction)
376+
375377
ctx = await self.get_application_context(interaction)
376378
ctx.command = command
377379
self.dispatch("application_command", ctx)
@@ -456,7 +458,7 @@ def command(self, **kwargs):
456458
457459
.. note::
458460
459-
This decorator is overridden by :class:`commands.Bot`.
461+
This decorator is overridden by :class:`discord.ext.commands.Bot`.
460462
461463
.. versionadded:: 2.0
462464
@@ -569,18 +571,16 @@ async def on_application_command_error(
569571
570572
This only fires if you do not specify any listeners for command error.
571573
"""
572-
# TODO
573-
# if self.extra_events.get('on_application_command_error', None):
574-
# return
574+
if self.extra_events.get('on_application_command_error', None):
575+
return
575576

576577
command = context.command
577578
if command and command.has_error_handler():
578579
return
579580

580-
# TODO
581-
# cog = context.cog
582-
# if cog and cog.has_error_handler():
583-
# return
581+
cog = context.cog
582+
if cog and cog.has_error_handler():
583+
return
584584

585585
print(f"Ignoring exception in command {context.command}:", file=sys.stderr)
586586
traceback.print_exception(

discord/commands/commands.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
import functools
3131
import inspect
3232
from collections import OrderedDict
33-
from typing import Any, Callable, Dict, List, Optional, Union
33+
from typing import Any, Callable, Dict, List, Optional, Union, TYPE_CHECKING
3434

3535
from ..enums import SlashCommandOptionType, ChannelType
3636
from ..member import Member
@@ -60,6 +60,9 @@
6060
"MessageCommand",
6161
)
6262

63+
if TYPE_CHECKING:
64+
from ..interactions import Interaction
65+
6366
def wrap_callback(coro):
6467
@functools.wraps(coro)
6568
async def wrapped(*args, **kwargs):
@@ -351,7 +354,7 @@ def __init__(self, func: Callable, *args, **kwargs) -> None:
351354
self.cog = None
352355

353356
params = self._get_signature_parameters()
354-
self.options = self._parse_options(params)
357+
self.options: List[Option] = self._parse_options(params)
355358

356359
try:
357360
checks = func.__commands_checks__
@@ -418,6 +421,7 @@ def _parse_options(self, params) -> List[Option]:
418421

419422
if option.name is None:
420423
option.name = p_name
424+
option._parameter_name = p_name
421425

422426
final_options.append(option)
423427

@@ -476,17 +480,28 @@ async def _invoke(self, ctx: ApplicationContext) -> None:
476480
elif op.input_type == SlashCommandOptionType.string and op._converter is not None:
477481
arg = await op._converter.convert(ctx, arg)
478482

479-
kwargs[op.name] = arg
483+
kwargs[op._parameter_name] = arg
480484

481485
for o in self.options:
482-
if o.name not in kwargs:
483-
kwargs[o.name] = o.default
486+
if o._parameter_name not in kwargs:
487+
kwargs[o._parameter_name] = o.default
484488

485489
if self.cog is not None:
486490
await self.callback(self.cog, ctx, **kwargs)
487491
else:
488492
await self.callback(ctx, **kwargs)
489493

494+
async def invoke_autocomplete_callback(self, interaction: Interaction):
495+
for op in interaction.data.get("options", []):
496+
if op.get("focused", False):
497+
option = find(lambda o: o.name == op["name"], self.options)
498+
result = await option.autocomplete(interaction, op.get("value", None))
499+
choices = [
500+
o if isinstance(o, OptionChoice) else OptionChoice(o)
501+
for o in result
502+
]
503+
await interaction.response.send_autocomplete_result(choices=choices)
504+
490505
def qualified_name(self):
491506
return self.name
492507

@@ -581,13 +596,21 @@ def __init__(
581596
if not (isinstance(self.max_value, minmax_types) or self.min_value is None):
582597
raise TypeError(f"Expected {minmax_typehint} for max_value, got \"{type(self.max_value).__name__}\"")
583598

599+
self.autocomplete = kwargs.pop("autocomplete", None)
600+
if (
601+
self.autocomplete and
602+
not asyncio.iscoroutinefunction(self.autocomplete)
603+
):
604+
raise TypeError("Autocomplete callback must be a coroutine.")
605+
584606
def to_dict(self) -> Dict:
585607
as_dict = {
586608
"name": self.name,
587609
"description": self.description,
588610
"type": self.input_type.value,
589611
"required": self.required,
590612
"choices": [c.to_dict() for c in self.choices],
613+
"autocomplete": bool(self.autocomplete)
591614
}
592615
if self.channel_types:
593616
as_dict["channel_types"] = [t.value for t in self.channel_types]
@@ -722,6 +745,13 @@ async def _invoke(self, ctx: ApplicationContext) -> None:
722745
ctx.interaction.data = option
723746
await command.invoke(ctx)
724747

748+
async def invoke_autocomplete_callback(self, interaction: Interaction) -> None:
749+
option = interaction.data["options"][0]
750+
command = find(lambda x: x.name == option["name"], self.subcommands)
751+
interaction.data = option
752+
await command.invoke_autocomplete_callback(interaction)
753+
754+
725755
class ContextMenuCommand(ApplicationCommand):
726756
r"""A class that implements the protocol for context menu commands.
727757

discord/commands/context.py

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2323
DEALINGS IN THE SOFTWARE.
2424
"""
25+
from __future__ import annotations
2526

2627
from typing import TYPE_CHECKING, Optional, Union
2728

@@ -31,6 +32,9 @@
3132
import discord
3233
from discord.state import ConnectionState
3334

35+
from .commands import ApplicationCommand
36+
from ..cog import Cog
37+
3438
from ..guild import Guild
3539
from ..interactions import Interaction, InteractionResponse
3640
from ..member import Member
@@ -63,7 +67,7 @@ class ApplicationContext(discord.abc.Messageable):
6367
def __init__(self, bot: "discord.Bot", interaction: Interaction):
6468
self.bot = bot
6569
self.interaction = interaction
66-
self.command = None
70+
self.command: ApplicationCommand = None # type: ignore
6771
self._state: ConnectionState = self.interaction._state
6872

6973
async def _get_channel(self) -> discord.abc.Messageable:
@@ -130,3 +134,11 @@ async def delete(self):
130134
@property
131135
def edit(self):
132136
return self.interaction.edit_original_message
137+
138+
@property
139+
def cog(self) -> Optional[Cog]:
140+
"""Optional[:class:`.Cog`]: Returns the cog associated with this context's command. None if it does not exist."""
141+
if self.command is None:
142+
return None
143+
144+
return self.command.cog

discord/enums.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,13 @@ def __int__(self):
596596
return self.value
597597

598598

599+
class ApplicationType(Enum):
600+
game = 1
601+
music = 2
602+
ticketed_events = 3
603+
guild_role_subscriptions = 4
604+
605+
599606
class StagePrivacyLevel(Enum):
600607
public = 1
601608
closed = 2
@@ -642,7 +649,7 @@ def from_datatype(cls, datatype):
642649
if issubclass(datatype, float):
643650
return cls.number
644651

645-
if datatype.__name__ == "Member":
652+
if datatype.__name__ in ["Member", "User"]:
646653
return cls.user
647654
if datatype.__name__ in [
648655
"GuildChannel", "TextChannel",
@@ -660,22 +667,40 @@ def from_datatype(cls, datatype):
660667

661668

662669
class EmbeddedActivity(Enum):
670+
awkword = 879863881349087252
663671
betrayal = 773336526917861400
664-
chess = 832012586023256104
665-
chess_dev = 832012774040141894
672+
cg2_qa = 832012815819604009
673+
cg2_staging = 832012730599735326
674+
cg3_dev = 832012682520428625
675+
cg3_prod = 832013003968348200
676+
cg3_qa = 832012894068801636
677+
cg3_staging = 832012938398400562
678+
cg4_dev = 832013108234289153
679+
cg4_prod = 832025144389533716
680+
cg4_qa = 832025114077298718
681+
cg4_staging = 832025061657280566
682+
chess_in_the_park_dev = 832012586023256104
683+
chess_in_the_park = 832012774040141894
684+
decoders_dev = 891001866073296967
666685
doodle_crew = 878067389634314250
667-
fishing = 814288819477020702
686+
doodle_crew_dev = 878067427668275241
687+
fishington = 814288819477020702
668688
letter_tile = 879863686565621790
669-
poker = 755827207812677713
689+
pn_staging = 763116274876022855
690+
poker_night = 755827207812677713
691+
poker_qa = 801133024841957428
692+
putts = 832012854282158180
693+
sketchy_artist = 879864070101172255
694+
sketchy_artist_dev = 879864104980979792
670695
spell_cast = 852509694341283871
671696
watch_together = 880218394199220334
672697
watch_together_dev = 880218832743055411
673-
word_snack = 879863976006127627
674-
youtube = 755600276941176913
698+
word_snacks = 879863976006127627
699+
word_snacks_dev = 879864010126786570
700+
youtube_together = 755600276941176913
675701

676702
T = TypeVar('T')
677703

678-
679704
def create_unknown_value(cls: Type[T], val: Any) -> T:
680705
value_cls = cls._enum_value_cls_ # type: ignore
681706
name = f'unknown_{val}'

discord/ext/commands/help.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,9 @@ async def filter_commands(self, commands, *, sort=False, key=None):
559559
if sort and key is None:
560560
key = lambda c: c.name
561561

562-
iterator = commands if self.show_hidden else filter(lambda c: not c.hidden, commands)
562+
# Ignore Application Commands cause they dont have hidden/docs
563+
prefix_commands = [command for command in commands if not isinstance(command, discord.commands.ApplicationCommand)]
564+
iterator = prefix_commands if self.show_hidden else filter(lambda c: not c.hidden, prefix_commands)
563565

564566
if self.verify_checks is False:
565567
# if we do not need to verify the checks then we can just

0 commit comments

Comments
 (0)