Skip to content

Unpack usage where possible #10189

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 24 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions discord/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@
T = TypeVar('T', bound=VoiceProtocol)

if TYPE_CHECKING:
from typing_extensions import Self
from typing_extensions import Self, Unpack

Check warning on line 76 in discord/abc.py

View workflow job for this annotation

GitHub Actions / check 3.x

Import "typing_extensions" could not be resolved from source (reportMissingModuleSource)

from .client import Client
from .user import ClientUser
Expand Down Expand Up @@ -108,6 +108,7 @@
from .types.snowflake import (
SnowflakeList,
)
from .permissions import _PermissionOverwriteKwargs

PartialMessageableChannel = Union[TextChannel, VoiceChannel, StageChannel, Thread, DMChannel, PartialMessageable]
MessageableChannel = Union[PartialMessageableChannel, GroupChannel]
Expand Down Expand Up @@ -886,7 +887,7 @@
target: Union[Member, Role],
*,
reason: Optional[str] = ...,
**permissions: Optional[bool],
**permissions: Unpack[_PermissionOverwriteKwargs],
) -> None:
...

Expand All @@ -896,7 +897,7 @@
*,
overwrite: Any = _undefined,
reason: Optional[str] = None,
**permissions: Optional[bool],
**permissions: Unpack[_PermissionOverwriteKwargs],
) -> None:
r"""|coro|

Expand Down
7 changes: 4 additions & 3 deletions discord/app_commands/checks.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,9 @@
T = TypeVar('T')

if TYPE_CHECKING:
from typing_extensions import Self
from typing_extensions import Self, Unpack
from ..interactions import Interaction
from ..permissions import _PermissionsKwargs

CooldownFunction = Union[
Callable[[Interaction[Any]], Coroutine[Any, Any, T]],
Expand Down Expand Up @@ -286,7 +287,7 @@ def predicate(interaction: Interaction) -> bool:
return check(predicate)


def has_permissions(**perms: bool) -> Callable[[T], T]:
def has_permissions(**perms: Unpack[_PermissionsKwargs]) -> Callable[[T], T]:
r"""A :func:`~discord.app_commands.check` that is added that checks if the member
has all of the permissions necessary.

Expand Down Expand Up @@ -341,7 +342,7 @@ def predicate(interaction: Interaction) -> bool:
return check(predicate)


def bot_has_permissions(**perms: bool) -> Callable[[T], T]:
def bot_has_permissions(**perms: Unpack[_PermissionsKwargs]) -> Callable[[T], T]:
"""Similar to :func:`has_permissions` except checks if the bot itself has
the permissions listed. This relies on :attr:`discord.Interaction.app_permissions`.

Expand Down
5 changes: 3 additions & 2 deletions discord/app_commands/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@
from ..utils import resolve_annotation, MISSING, is_inside_class, maybe_coroutine, async_all, _shorten, _to_kebab_case

if TYPE_CHECKING:
from typing_extensions import ParamSpec, Concatenate
from typing_extensions import ParamSpec, Concatenate, Unpack
from ..interactions import Interaction
from ..abc import Snowflake
from .namespace import Namespace
Expand All @@ -73,6 +73,7 @@
# However, for type hinting purposes it's unfortunately necessary for one to
# reference the other to prevent type checking errors in callbacks
from discord.ext import commands
from discord.permissions import _PermissionsKwargs

ErrorFunc = Callable[[Interaction, AppCommandError], Coroutine[Any, Any, None]]

Expand Down Expand Up @@ -2821,7 +2822,7 @@ def inner(f: T) -> T:
return inner


def default_permissions(perms_obj: Optional[Permissions] = None, /, **perms: bool) -> Callable[[T], T]:
def default_permissions(perms_obj: Optional[Permissions] = None, /, **perms: Unpack[_PermissionsKwargs]) -> Callable[[T], T]:
r"""A decorator that sets the default permissions needed to execute this command.

When this decorator is used, by default users must have these permissions to execute the command.
Expand Down
55 changes: 50 additions & 5 deletions discord/channel.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
Sequence,
Tuple,
TypeVar,
TypedDict,
Union,
overload,
)
Expand Down Expand Up @@ -85,7 +86,7 @@
)

if TYPE_CHECKING:
from typing_extensions import Self
from typing_extensions import Self, Unpack

Check warning on line 89 in discord/channel.py

View workflow job for this annotation

GitHub Actions / check 3.x

Import "typing_extensions" could not be resolved from source (reportMissingModuleSource)

from .types.threads import ThreadArchiveDuration
from .role import Role
Expand Down Expand Up @@ -120,6 +121,50 @@

OverwriteKeyT = TypeVar('OverwriteKeyT', Role, BaseUser, Object, Union[Role, Member, Object])

class _CreateChannelWithCategory(TypedDict, total=False):
category: Optional[CategoryChannel]

class _CreateNewsChannel(TypedDict, total=False):
news: bool

class _BaseCreateChannelOptions(TypedDict, total=False):
reason: Optional[str]
position: int

class _CreateTextChannelOptions(_BaseCreateChannelOptions, total=False):
topic: str
slowmode_delay: int
nsfw: bool
overwrites: Mapping[Union[Role, Member, Object], PermissionOverwrite]
default_auto_archive_duration: int
default_thread_slowmode_delay: int

class _CreateVoiceChannelOptions(_BaseCreateChannelOptions, total=False):
bitrate: int
user_limit: int
rtc_region: Optional[str]
video_quality_mode: VideoQualityMode
overwrites: Mapping[Union[Role, Member, Object], PermissionOverwrite]

class _CreateStageChannelOptions(_CreateVoiceChannelOptions, total=False):
bitrate: int
user_limit: int
rtc_region: Optional[str]
video_quality_mode: VideoQualityMode
overwrites: Mapping[Union[Role, Member, Object], PermissionOverwrite]

class _CreateForumChannelOptions(_CreateTextChannelOptions, total=False):
topic: str
slowmode_delay: int
nsfw: bool
overwrites: Mapping[Union[Role, Member, Object], PermissionOverwrite]
default_auto_archive_duration: int
default_thread_slowmode_delay: int
default_sort_order: ForumOrderType
default_reaction_emoji: EmojiInputType
default_layout: ForumLayoutType
available_tags: Sequence[ForumTag]


class ThreadWithMessage(NamedTuple):
thread: Thread
Expand Down Expand Up @@ -2194,7 +2239,7 @@
r.sort(key=lambda c: (c.position, c.id))
return r

async def create_text_channel(self, name: str, **options: Any) -> TextChannel:
async def create_text_channel(self, name: str, **options: Unpack[_CreateTextChannelOptions]) -> TextChannel:
"""|coro|

A shortcut method to :meth:`Guild.create_text_channel` to create a :class:`TextChannel` in the category.
Expand All @@ -2206,7 +2251,7 @@
"""
return await self.guild.create_text_channel(name, category=self, **options)

async def create_voice_channel(self, name: str, **options: Any) -> VoiceChannel:
async def create_voice_channel(self, name: str, **options: Unpack[_CreateVoiceChannelOptions]) -> VoiceChannel:
"""|coro|

A shortcut method to :meth:`Guild.create_voice_channel` to create a :class:`VoiceChannel` in the category.
Expand All @@ -2218,7 +2263,7 @@
"""
return await self.guild.create_voice_channel(name, category=self, **options)

async def create_stage_channel(self, name: str, **options: Any) -> StageChannel:
async def create_stage_channel(self, name: str, **options: Unpack[_CreateStageChannelOptions]) -> StageChannel:
"""|coro|

A shortcut method to :meth:`Guild.create_stage_channel` to create a :class:`StageChannel` in the category.
Expand All @@ -2232,7 +2277,7 @@
"""
return await self.guild.create_stage_channel(name, category=self, **options)

async def create_forum(self, name: str, **options: Any) -> ForumChannel:
async def create_forum(self, name: str, **options: Unpack[_CreateForumChannelOptions]) -> ForumChannel:
"""|coro|

A shortcut method to :meth:`Guild.create_forum` to create a :class:`ForumChannel` in the category.
Expand Down
27 changes: 25 additions & 2 deletions discord/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
Tuple,
Type,
TypeVar,
TypedDict,
Union,
overload,
)
Expand Down Expand Up @@ -82,7 +83,7 @@
if TYPE_CHECKING:
from types import TracebackType

from typing_extensions import Self
from typing_extensions import Self, Unpack

Check warning on line 86 in discord/client.py

View workflow job for this annotation

GitHub Actions / check 3.x

Import "typing_extensions" could not be resolved from source (reportMissingModuleSource)

from .abc import Messageable, PrivateChannel, Snowflake, SnowflakeTime
from .app_commands import Command, ContextMenu
Expand Down Expand Up @@ -120,6 +121,28 @@
from .audit_logs import AuditLogEntry
from .poll import PollAnswer
from .subscription import Subscription
from .flags import MemberCacheFlags

class _ClientOptions(TypedDict, total=False):
max_messages: int
proxy: str
proxy_auth: aiohttp.BasicAuth
shard_id: int
shard_count: int
application_id: int
member_cache_flags: MemberCacheFlags
chunk_guilds_at_startup: bool
status: Status
activity: BaseActivity
allowed_mentions: AllowedMentions
heartbeat_timeout: float
guild_ready_timeout: float
assume_unsync_clock: bool
enable_debug_events: bool
enable_raw_presences: bool
http_trace: aiohttp.TraceConfig
max_ratelimit_timeout: float
connector: aiohttp.BaseConnector


# fmt: off
Expand Down Expand Up @@ -272,7 +295,7 @@
The websocket gateway the client is currently connected to. Could be ``None``.
"""

def __init__(self, *, intents: Intents, **options: Any) -> None:
def __init__(self, *, intents: Intents, **options: Unpack[_ClientOptions]) -> None:
self.loop: asyncio.AbstractEventLoop = _loop
# self.ws is set in the connect method
self.ws: DiscordWebSocket = None # type: ignore
Expand Down
46 changes: 36 additions & 10 deletions discord/ext/commands/bot.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
from .hybrid import hybrid_command, hybrid_group, HybridCommand, HybridGroup

if TYPE_CHECKING:
from typing_extensions import Self
from typing_extensions import Self, Unpack

import importlib.machinery

Expand All @@ -80,12 +80,24 @@
MaybeAwaitableFunc,
)
from .core import Command
from .hybrid import CommandCallback, ContextT, P
from .hybrid import CommandCallback, ContextT, P, _HybridCommandDecoratorKwargs, _HybridGroupDecoratorKwargs
from discord.client import _ClientOptions
from discord.shard import _AutoShardedClientOptions

_Prefix = Union[Iterable[str], str]
_PrefixCallable = MaybeAwaitableFunc[[BotT, Message], _Prefix]
PrefixType = Union[_Prefix, _PrefixCallable[BotT]]

class _BotOptions(_ClientOptions, total=False):
owner_id: int
owner_ids: Collection[int]
strip_after_prefix: bool
case_insensitive: bool

class _AutoShardedBotOptions(_AutoShardedClientOptions, _BotOptions):
...


__all__ = (
'when_mentioned',
'when_mentioned_or',
Expand Down Expand Up @@ -169,7 +181,7 @@ def __init__(
allowed_contexts: app_commands.AppCommandContext = MISSING,
allowed_installs: app_commands.AppInstallationType = MISSING,
intents: discord.Intents,
**options: Any,
**options: Unpack[_BotOptions],
) -> None:
super().__init__(intents=intents, **options)
self.command_prefix: PrefixType[BotT] = command_prefix # type: ignore
Expand Down Expand Up @@ -281,7 +293,7 @@ def hybrid_command(
name: Union[str, app_commands.locale_str] = MISSING,
with_app_command: bool = True,
*args: Any,
**kwargs: Any,
**kwargs: Unpack[_HybridCommandDecoratorKwargs], # type: ignore # name, with_app_command
) -> Callable[[CommandCallback[Any, ContextT, P, T]], HybridCommand[Any, P, T]]:
"""A shortcut decorator that invokes :func:`~discord.ext.commands.hybrid_command` and adds it to
the internal command list via :meth:`add_command`.
Expand All @@ -293,8 +305,8 @@ def hybrid_command(
"""

def decorator(func: CommandCallback[Any, ContextT, P, T]):
kwargs.setdefault('parent', self)
result = hybrid_command(name=name, *args, with_app_command=with_app_command, **kwargs)(func)
kwargs.setdefault('parent', self) # type: ignore # parent is not for the user to set
result = hybrid_command(name=name, *args, with_app_command=with_app_command, **kwargs)(func) # type: ignore # name, with_app_command
self.add_command(result)
return result

Expand All @@ -305,7 +317,7 @@ def hybrid_group(
name: Union[str, app_commands.locale_str] = MISSING,
with_app_command: bool = True,
*args: Any,
**kwargs: Any,
**kwargs: Unpack[_HybridGroupDecoratorKwargs], # type: ignore # name, with_app_command
) -> Callable[[CommandCallback[Any, ContextT, P, T]], HybridGroup[Any, P, T]]:
"""A shortcut decorator that invokes :func:`~discord.ext.commands.hybrid_group` and adds it to
the internal command list via :meth:`add_command`.
Expand All @@ -317,8 +329,8 @@ def hybrid_group(
"""

def decorator(func: CommandCallback[Any, ContextT, P, T]):
kwargs.setdefault('parent', self)
result = hybrid_group(name=name, *args, with_app_command=with_app_command, **kwargs)(func)
kwargs.setdefault('parent', self) # type: ignore # parent is not for the user to set
result = hybrid_group(name=name, *args, with_app_command=with_app_command, **kwargs)(func) # type: ignore # name, with_app_command
self.add_command(result)
return result

Expand Down Expand Up @@ -1527,4 +1539,18 @@ class AutoShardedBot(BotBase, discord.AutoShardedClient):
.. versionadded:: 2.0
"""

pass
if TYPE_CHECKING:

def __init__(
self,
command_prefix: PrefixType[BotT],
*,
help_command: Optional[HelpCommand] = _default,
tree_cls: Type[app_commands.CommandTree[Any]] = app_commands.CommandTree,
description: Optional[str] = None,
allowed_contexts: app_commands.AppCommandContext = MISSING,
allowed_installs: app_commands.AppInstallationType = MISSING,
intents: discord.Intents,
**kwargs: Unpack[_AutoShardedBotOptions],
) -> None:
...
18 changes: 15 additions & 3 deletions discord/ext/commands/cog.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,18 +44,30 @@
Tuple,
TypeVar,
Union,
TypedDict,
)

from ._types import _BaseCommand, BotT

if TYPE_CHECKING:
from typing_extensions import Self
from typing_extensions import Self, Unpack
from discord.abc import Snowflake
from discord._types import ClientT

from .bot import BotBase
from .context import Context
from .core import Command
from .core import Command, _CommandDecoratorKwargs

class _CogKwargs(TypedDict, total=False):
name: str
group_name: Union[str, app_commands.locale_str]
description: str
group_description: Union[str, app_commands.locale_str]
group_nsfw: bool
group_auto_locale_strings: bool
group_extras: Dict[Any, Any]
command_attrs: _CommandDecoratorKwargs


__all__ = (
'CogMeta',
Expand Down Expand Up @@ -169,7 +181,7 @@ async def bar(self, ctx):
__cog_app_commands__: List[Union[app_commands.Group, app_commands.Command[Any, ..., Any]]]
__cog_listeners__: List[Tuple[str, str]]

def __new__(cls, *args: Any, **kwargs: Any) -> CogMeta:
def __new__(cls, *args: Any, **kwargs: Unpack[_CogKwargs]) -> CogMeta:
name, bases, attrs = args
if any(issubclass(base, app_commands.Group) for base in bases):
raise TypeError(
Expand Down
Loading
Loading