Skip to content

Commit 5933635

Browse files
authored
Merge branch 'Pycord-Development:master' into master
2 parents d1a2d5d + 26c85e4 commit 5933635

File tree

7 files changed

+101
-43
lines changed

7 files changed

+101
-43
lines changed

.github/workflows/bypass-review.yml

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

discord/bot.py

Lines changed: 12 additions & 10 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)

discord/commands/commands.py

Lines changed: 31 additions & 2 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__
@@ -487,6 +490,17 @@ async def _invoke(self, ctx: ApplicationContext) -> None:
487490
else:
488491
await self.callback(ctx, **kwargs)
489492

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

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

598+
self.autocomplete = kwargs.pop("autocomplete", None)
599+
if (
600+
self.autocomplete and
601+
not asyncio.iscoroutinefunction(self.autocomplete)
602+
):
603+
raise TypeError("Autocomplete callback must be a coroutine.")
604+
584605
def to_dict(self) -> Dict:
585606
as_dict = {
586607
"name": self.name,
587608
"description": self.description,
588609
"type": self.input_type.value,
589610
"required": self.required,
590611
"choices": [c.to_dict() for c in self.choices],
612+
"autocomplete": bool(self.autocomplete)
591613
}
592614
if self.channel_types:
593615
as_dict["channel_types"] = [t.value for t in self.channel_types]
@@ -722,6 +744,13 @@ async def _invoke(self, ctx: ApplicationContext) -> None:
722744
ctx.interaction.data = option
723745
await command.invoke(ctx)
724746

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

discord/guild.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -240,6 +240,10 @@ class Guild(Hashable):
240240
The number goes from 0 to 3 inclusive.
241241
premium_subscription_count: :class:`int`
242242
The number of "boosts" this guild currently has.
243+
premium_progress_bar_enabled: :class:`bool`
244+
Indicates if the guild has premium progress bar enabled.
245+
246+
.. versionadded:: 2.0
243247
preferred_locale: Optional[:class:`str`]
244248
The preferred locale for the guild. Used when filtering Server Discovery
245249
results to a specific language.
@@ -270,6 +274,7 @@ class Guild(Hashable):
270274
'max_video_channel_users',
271275
'premium_tier',
272276
'premium_subscription_count',
277+
'premium_progress_bar_enabled',
273278
'preferred_locale',
274279
'nsfw_level',
275280
'_members',
@@ -450,6 +455,7 @@ def _from_data(self, guild: GuildPayload) -> None:
450455
self.max_video_channel_users: Optional[int] = guild.get('max_video_channel_users')
451456
self.premium_tier: int = guild.get('premium_tier', 0)
452457
self.premium_subscription_count: int = guild.get('premium_subscription_count') or 0
458+
self.premium_progress_bar_enabled: bool = guild.get('premium_progress_bar_enabled') or False
453459
self._system_channel_flags: int = guild.get('system_channel_flags', 0)
454460
self.preferred_locale: Optional[str] = guild.get('preferred_locale')
455461
self._discovery_splash: Optional[str] = guild.get('discovery_splash')
@@ -1371,6 +1377,7 @@ async def edit(
13711377
preferred_locale: str = MISSING,
13721378
rules_channel: Optional[TextChannel] = MISSING,
13731379
public_updates_channel: Optional[TextChannel] = MISSING,
1380+
premium_progress_bar_enabled: bool = MISSING,
13741381
) -> Guild:
13751382
r"""|coro|
13761383
@@ -1448,6 +1455,8 @@ async def edit(
14481455
The new channel that is used for public updates from Discord. This is only available to
14491456
guilds that contain ``PUBLIC`` in :attr:`Guild.features`. Could be ``None`` for no
14501457
public updates channel.
1458+
premium_progress_bar_enabled: :class:`bool`
1459+
Whether the guild should have premium progress bar enabled.
14511460
reason: Optional[:class:`str`]
14521461
The reason for editing this guild. Shows up on the audit log.
14531462
@@ -1578,6 +1587,9 @@ async def edit(
15781587
)
15791588

15801589
fields['features'] = features
1590+
1591+
if premium_progress_bar_enabled is not MISSING:
1592+
fields['premium_progress_bar_enabled'] = premium_progress_bar_enabled
15811593

15821594
data = await http.edit_guild(self.id, reason=reason, **fields)
15831595
return Guild(data=data, state=self._state)

discord/http.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1077,6 +1077,7 @@ def edit_guild(self, guild_id: Snowflake, *, reason: Optional[str] = None, **fie
10771077
'rules_channel_id',
10781078
'public_updates_channel_id',
10791079
'preferred_locale',
1080+
'premium_progress_bar_enabled',
10801081
)
10811082

10821083
payload = {k: v for k, v in fields.items() if k in valid_keys}

discord/interactions.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,11 +61,13 @@
6161
from .ui.view import View
6262
from .channel import VoiceChannel, StageChannel, TextChannel, CategoryChannel, StoreChannel, PartialMessageable
6363
from .threads import Thread
64+
from .commands import OptionChoice
6465

6566
InteractionChannel = Union[
6667
VoiceChannel, StageChannel, TextChannel, CategoryChannel, StoreChannel, Thread, PartialMessageable
6768
]
6869

70+
6971
MISSING: Any = utils.MISSING
7072

7173

@@ -692,7 +694,49 @@ async def edit_message(
692694

693695
self._responded = True
694696

697+
async def send_autocomplete_result(
698+
self,
699+
*,
700+
choices: List[OptionChoice],
701+
) -> None:
702+
"""|coro|
703+
Responds to this interaction by sending the autocomplete choices.
704+
705+
Parameters
706+
-----------
707+
choices: List[:class:`OptionChoice`]
708+
A list of choices.
709+
710+
Raises
711+
-------
712+
HTTPException
713+
Sending the result failed.
714+
InteractionResponded
715+
This interaction has already been responded to before.
716+
"""
717+
if self._responded:
718+
raise InteractionResponded(self._parent)
719+
720+
parent = self._parent
695721

722+
if parent.type is not InteractionType.auto_complete:
723+
return
724+
725+
payload = {
726+
"choices": [c.to_dict() for c in choices]
727+
}
728+
729+
adapter = async_context.get()
730+
await adapter.create_interaction_response(
731+
parent.id,
732+
parent.token,
733+
session=parent._session,
734+
type=InteractionResponseType.auto_complete_result.value,
735+
data=payload,
736+
)
737+
738+
self._responded = True
739+
696740
class _InteractionMessageState:
697741
__slots__ = ('_parent', '_interaction')
698742

discord/types/guild.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ class _GuildOptional(TypedDict, total=False):
6666
max_presences: Optional[int]
6767
max_members: int
6868
premium_subscription_count: int
69+
premium_progress_bar_enabled: bool
6970
max_video_channel_users: int
7071

7172

0 commit comments

Comments
 (0)