Skip to content

Commit

Permalink
Merge branch 'Pycord-Development:master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
Lulalaby authored Oct 30, 2021
2 parents d1a2d5d + 26c85e4 commit 5933635
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 43 deletions.
31 changes: 0 additions & 31 deletions .github/workflows/bypass-review.yml

This file was deleted.

22 changes: 12 additions & 10 deletions discord/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@

from .client import Client
from .shard import AutoShardedClient
from .utils import MISSING, get, async_all
from .utils import MISSING, get, find, async_all
from .commands import (
SlashCommand,
SlashCommandGroup,
Expand All @@ -59,6 +59,7 @@

from .errors import Forbidden, DiscordException
from .interactions import Interaction
from .enums import InteractionType

CoroFunc = Callable[..., Coroutine[Any, Any, Any]]
CFT = TypeVar('CFT', bound=CoroFunc)
Expand Down Expand Up @@ -86,7 +87,7 @@ def pending_application_commands(self):
return self._pending_application_commands

@property
def commands(self) -> List[Union[ApplicationCommand, ...]]:
def commands(self) -> List[Union[ApplicationCommand, Any]]:
commands = list(self.application_commands.values())
if self._supports_prefixed_commands:
commands += self.prefixed_commands
Expand Down Expand Up @@ -188,7 +189,7 @@ async def register_commands(self) -> None:
cmd = get(
self.pending_application_commands,
name=i["name"],
description=i["description"],
guild_ids=None,
type=i["type"],
)
self.application_commands[i["id"]] = cmd
Expand Down Expand Up @@ -224,12 +225,7 @@ async def register_commands(self) -> None:
raise
else:
for i in cmds:
cmd = get(
self.pending_application_commands,
name=i["name"],
description=i["description"],
type=i["type"],
)
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)
self.application_commands[i["id"]] = cmd

# Permissions
Expand Down Expand Up @@ -364,14 +360,20 @@ async def process_application_commands(self, interaction: Interaction) -> None:
interaction: :class:`discord.Interaction`
The interaction to process
"""
if not interaction.is_command():
if interaction.type not in (
InteractionType.application_command,
InteractionType.auto_complete
):
return

try:
command = self.application_commands[interaction.data["id"]]
except KeyError:
self.dispatch("unknown_command", interaction)
else:
if interaction.type is InteractionType.auto_complete:
return await command.invoke_autocomplete_callback(interaction)

ctx = await self.get_application_context(interaction)
ctx.command = command
self.dispatch("application_command", ctx)
Expand Down
33 changes: 31 additions & 2 deletions discord/commands/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import functools
import inspect
from collections import OrderedDict
from typing import Any, Callable, Dict, List, Optional, Union
from typing import Any, Callable, Dict, List, Optional, Union, TYPE_CHECKING

from ..enums import SlashCommandOptionType, ChannelType
from ..member import Member
Expand Down Expand Up @@ -60,6 +60,9 @@
"MessageCommand",
)

if TYPE_CHECKING:
from ..interactions import Interaction

def wrap_callback(coro):
@functools.wraps(coro)
async def wrapped(*args, **kwargs):
Expand Down Expand Up @@ -351,7 +354,7 @@ def __init__(self, func: Callable, *args, **kwargs) -> None:
self.cog = None

params = self._get_signature_parameters()
self.options = self._parse_options(params)
self.options: List[Option] = self._parse_options(params)

try:
checks = func.__commands_checks__
Expand Down Expand Up @@ -487,6 +490,17 @@ async def _invoke(self, ctx: ApplicationContext) -> None:
else:
await self.callback(ctx, **kwargs)

async def invoke_autocomplete_callback(self, interaction: Interaction):
for op in interaction.data.get("options", []):
if op.get("focused", False):
option = find(lambda o: o.name == op["name"], self.options)
result = await option.autocomplete(interaction, op.get("value", None))
choices = [
o if isinstance(o, OptionChoice) else OptionChoice(o)
for o in result
]
await interaction.response.send_autocomplete_result(choices=choices)

def qualified_name(self):
return self.name

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

self.autocomplete = kwargs.pop("autocomplete", None)
if (
self.autocomplete and
not asyncio.iscoroutinefunction(self.autocomplete)
):
raise TypeError("Autocomplete callback must be a coroutine.")

def to_dict(self) -> Dict:
as_dict = {
"name": self.name,
"description": self.description,
"type": self.input_type.value,
"required": self.required,
"choices": [c.to_dict() for c in self.choices],
"autocomplete": bool(self.autocomplete)
}
if self.channel_types:
as_dict["channel_types"] = [t.value for t in self.channel_types]
Expand Down Expand Up @@ -722,6 +744,13 @@ async def _invoke(self, ctx: ApplicationContext) -> None:
ctx.interaction.data = option
await command.invoke(ctx)

async def invoke_autocomplete_callback(self, interaction: Interaction) -> None:
option = interaction.data["options"][0]
command = find(lambda x: x.name == option["name"], self.subcommands)
interaction.data = option
await command.invoke_autocomplete_callback(interaction)


class ContextMenuCommand(ApplicationCommand):
r"""A class that implements the protocol for context menu commands.
Expand Down
12 changes: 12 additions & 0 deletions discord/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,10 @@ class Guild(Hashable):
The number goes from 0 to 3 inclusive.
premium_subscription_count: :class:`int`
The number of "boosts" this guild currently has.
premium_progress_bar_enabled: :class:`bool`
Indicates if the guild has premium progress bar enabled.
.. versionadded:: 2.0
preferred_locale: Optional[:class:`str`]
The preferred locale for the guild. Used when filtering Server Discovery
results to a specific language.
Expand Down Expand Up @@ -270,6 +274,7 @@ class Guild(Hashable):
'max_video_channel_users',
'premium_tier',
'premium_subscription_count',
'premium_progress_bar_enabled',
'preferred_locale',
'nsfw_level',
'_members',
Expand Down Expand Up @@ -450,6 +455,7 @@ def _from_data(self, guild: GuildPayload) -> None:
self.max_video_channel_users: Optional[int] = guild.get('max_video_channel_users')
self.premium_tier: int = guild.get('premium_tier', 0)
self.premium_subscription_count: int = guild.get('premium_subscription_count') or 0
self.premium_progress_bar_enabled: bool = guild.get('premium_progress_bar_enabled') or False
self._system_channel_flags: int = guild.get('system_channel_flags', 0)
self.preferred_locale: Optional[str] = guild.get('preferred_locale')
self._discovery_splash: Optional[str] = guild.get('discovery_splash')
Expand Down Expand Up @@ -1371,6 +1377,7 @@ async def edit(
preferred_locale: str = MISSING,
rules_channel: Optional[TextChannel] = MISSING,
public_updates_channel: Optional[TextChannel] = MISSING,
premium_progress_bar_enabled: bool = MISSING,
) -> Guild:
r"""|coro|
Expand Down Expand Up @@ -1448,6 +1455,8 @@ async def edit(
The new channel that is used for public updates from Discord. This is only available to
guilds that contain ``PUBLIC`` in :attr:`Guild.features`. Could be ``None`` for no
public updates channel.
premium_progress_bar_enabled: :class:`bool`
Whether the guild should have premium progress bar enabled.
reason: Optional[:class:`str`]
The reason for editing this guild. Shows up on the audit log.
Expand Down Expand Up @@ -1578,6 +1587,9 @@ async def edit(
)

fields['features'] = features

if premium_progress_bar_enabled is not MISSING:
fields['premium_progress_bar_enabled'] = premium_progress_bar_enabled

data = await http.edit_guild(self.id, reason=reason, **fields)
return Guild(data=data, state=self._state)
Expand Down
1 change: 1 addition & 0 deletions discord/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,7 @@ def edit_guild(self, guild_id: Snowflake, *, reason: Optional[str] = None, **fie
'rules_channel_id',
'public_updates_channel_id',
'preferred_locale',
'premium_progress_bar_enabled',
)

payload = {k: v for k, v in fields.items() if k in valid_keys}
Expand Down
44 changes: 44 additions & 0 deletions discord/interactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,13 @@
from .ui.view import View
from .channel import VoiceChannel, StageChannel, TextChannel, CategoryChannel, StoreChannel, PartialMessageable
from .threads import Thread
from .commands import OptionChoice

InteractionChannel = Union[
VoiceChannel, StageChannel, TextChannel, CategoryChannel, StoreChannel, Thread, PartialMessageable
]


MISSING: Any = utils.MISSING


Expand Down Expand Up @@ -692,7 +694,49 @@ async def edit_message(

self._responded = True

async def send_autocomplete_result(
self,
*,
choices: List[OptionChoice],
) -> None:
"""|coro|
Responds to this interaction by sending the autocomplete choices.
Parameters
-----------
choices: List[:class:`OptionChoice`]
A list of choices.
Raises
-------
HTTPException
Sending the result failed.
InteractionResponded
This interaction has already been responded to before.
"""
if self._responded:
raise InteractionResponded(self._parent)

parent = self._parent

if parent.type is not InteractionType.auto_complete:
return

payload = {
"choices": [c.to_dict() for c in choices]
}

adapter = async_context.get()
await adapter.create_interaction_response(
parent.id,
parent.token,
session=parent._session,
type=InteractionResponseType.auto_complete_result.value,
data=payload,
)

self._responded = True

class _InteractionMessageState:
__slots__ = ('_parent', '_interaction')

Expand Down
1 change: 1 addition & 0 deletions discord/types/guild.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ class _GuildOptional(TypedDict, total=False):
max_presences: Optional[int]
max_members: int
premium_subscription_count: int
premium_progress_bar_enabled: bool
max_video_channel_users: int


Expand Down

0 comments on commit 5933635

Please sign in to comment.