Skip to content

Commit 983a9b8

Browse files
authored
Use Unpack where it's possible
1 parent 1343259 commit 983a9b8

File tree

13 files changed

+383
-103
lines changed

13 files changed

+383
-103
lines changed

discord/abc.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@
7777
T = TypeVar('T', bound=VoiceProtocol)
7878

7979
if TYPE_CHECKING:
80-
from typing_extensions import Self
80+
from typing_extensions import Self, Unpack
8181

8282
from .client import Client
8383
from .user import ClientUser
@@ -112,6 +112,7 @@
112112
from .types.snowflake import (
113113
SnowflakeList,
114114
)
115+
from .permissions import _PermissionOverwriteKwargs
115116

116117
PartialMessageableChannel = Union[TextChannel, VoiceChannel, StageChannel, Thread, DMChannel, PartialMessageable]
117118
MessageableChannel = Union[PartialMessageableChannel, GroupChannel]
@@ -915,7 +916,7 @@ async def set_permissions(
915916
target: Union[Member, Role],
916917
*,
917918
reason: Optional[str] = ...,
918-
**permissions: Optional[bool],
919+
**permissions: Unpack[_PermissionOverwriteKwargs],
919920
) -> None:
920921
...
921922

@@ -925,7 +926,7 @@ async def set_permissions(
925926
*,
926927
overwrite: Any = _undefined,
927928
reason: Optional[str] = None,
928-
**permissions: Optional[bool],
929+
**permissions: Unpack[_PermissionOverwriteKwargs],
929930
) -> None:
930931
r"""|coro|
931932

discord/app_commands/checks.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,9 @@
5555
T = TypeVar('T')
5656

5757
if TYPE_CHECKING:
58-
from typing_extensions import Self
58+
from typing_extensions import Self, Unpack
5959
from ..interactions import Interaction
60+
from ..permissions import _PermissionsKwargs
6061

6162
CooldownFunction = Union[
6263
Callable[[Interaction[Any]], Coroutine[Any, Any, T]],
@@ -286,7 +287,7 @@ def predicate(interaction: Interaction) -> bool:
286287
return check(predicate)
287288

288289

289-
def has_permissions(**perms: bool) -> Callable[[T], T]:
290+
def has_permissions(**perms: Unpack[_PermissionsKwargs]) -> Callable[[T], T]:
290291
r"""A :func:`~discord.app_commands.check` that is added that checks if the member
291292
has all of the permissions necessary.
292293
@@ -341,7 +342,7 @@ def predicate(interaction: Interaction) -> bool:
341342
return check(predicate)
342343

343344

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

discord/app_commands/commands.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
from ..utils import resolve_annotation, MISSING, is_inside_class, maybe_coroutine, async_all, _shorten, _to_kebab_case
6262

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

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

@@ -2840,7 +2841,7 @@ def inner(f: T) -> T:
28402841
return inner
28412842

28422843

2843-
def default_permissions(perms_obj: Optional[Permissions] = None, /, **perms: bool) -> Callable[[T], T]:
2844+
def default_permissions(perms_obj: Optional[Permissions] = None, /, **perms: Unpack[_PermissionsKwargs]) -> Callable[[T], T]:
28442845
r"""A decorator that sets the default permissions needed to execute this command.
28452846
28462847
When this decorator is used, by default users must have these permissions to execute the command.

discord/channel.py

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
Sequence,
4040
Tuple,
4141
TypeVar,
42+
TypedDict,
4243
Union,
4344
overload,
4445
)
@@ -85,7 +86,7 @@
8586
)
8687

8788
if TYPE_CHECKING:
88-
from typing_extensions import Self
89+
from typing_extensions import Self, Unpack
8990

9091
from .types.threads import ThreadArchiveDuration
9192
from .role import Role
@@ -120,6 +121,44 @@
120121

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

124+
class _BaseCreateChannelOptions(TypedDict, total=False):
125+
reason: Optional[str]
126+
position: int
127+
128+
class _CreateTextChannelOptions(_BaseCreateChannelOptions, total=False):
129+
topic: str
130+
slowmode_delay: int
131+
nsfw: bool
132+
overwrites: Mapping[Union[Role, Member, Object], PermissionOverwrite]
133+
default_auto_archive_duration: int
134+
default_thread_slowmode_delay: int
135+
136+
class _CreateVoiceChannelOptions(_BaseCreateChannelOptions, total=False):
137+
bitrate: int
138+
user_limit: int
139+
rtc_region: Optional[str]
140+
video_quality_mode: VideoQualityMode
141+
overwrites: Mapping[Union[Role, Member, Object], PermissionOverwrite]
142+
143+
class _CreateStageChannelOptions(_CreateVoiceChannelOptions, total=False):
144+
bitrate: int
145+
user_limit: int
146+
rtc_region: Optional[str]
147+
video_quality_mode: VideoQualityMode
148+
overwrites: Mapping[Union[Role, Member, Object], PermissionOverwrite]
149+
150+
class _CreateForumChannelOptions(_CreateTextChannelOptions, total=False):
151+
topic: str
152+
slowmode_delay: int
153+
nsfw: bool
154+
overwrites: Mapping[Union[Role, Member, Object], PermissionOverwrite]
155+
default_auto_archive_duration: int
156+
default_thread_slowmode_delay: int
157+
default_sort_order: ForumOrderType
158+
default_reaction_emoji: EmojiInputType
159+
default_layout: ForumLayoutType
160+
available_tags: Sequence[ForumTag]
161+
123162

124163
class ThreadWithMessage(NamedTuple):
125164
thread: Thread
@@ -2194,7 +2233,7 @@ def forums(self) -> List[ForumChannel]:
21942233
r.sort(key=lambda c: (c.position, c.id))
21952234
return r
21962235

2197-
async def create_text_channel(self, name: str, **options: Any) -> TextChannel:
2236+
async def create_text_channel(self, name: str, **options: Unpack[_CreateTextChannelOptions]) -> TextChannel:
21982237
"""|coro|
21992238
22002239
A shortcut method to :meth:`Guild.create_text_channel` to create a :class:`TextChannel` in the category.
@@ -2206,7 +2245,7 @@ async def create_text_channel(self, name: str, **options: Any) -> TextChannel:
22062245
"""
22072246
return await self.guild.create_text_channel(name, category=self, **options)
22082247

2209-
async def create_voice_channel(self, name: str, **options: Any) -> VoiceChannel:
2248+
async def create_voice_channel(self, name: str, **options: Unpack[_CreateVoiceChannelOptions]) -> VoiceChannel:
22102249
"""|coro|
22112250
22122251
A shortcut method to :meth:`Guild.create_voice_channel` to create a :class:`VoiceChannel` in the category.
@@ -2218,7 +2257,7 @@ async def create_voice_channel(self, name: str, **options: Any) -> VoiceChannel:
22182257
"""
22192258
return await self.guild.create_voice_channel(name, category=self, **options)
22202259

2221-
async def create_stage_channel(self, name: str, **options: Any) -> StageChannel:
2260+
async def create_stage_channel(self, name: str, **options: Unpack[_CreateStageChannelOptions]) -> StageChannel:
22222261
"""|coro|
22232262
22242263
A shortcut method to :meth:`Guild.create_stage_channel` to create a :class:`StageChannel` in the category.
@@ -2232,7 +2271,7 @@ async def create_stage_channel(self, name: str, **options: Any) -> StageChannel:
22322271
"""
22332272
return await self.guild.create_stage_channel(name, category=self, **options)
22342273

2235-
async def create_forum(self, name: str, **options: Any) -> ForumChannel:
2274+
async def create_forum(self, name: str, **options: Unpack[_CreateForumChannelOptions]) -> ForumChannel:
22362275
"""|coro|
22372276
22382277
A shortcut method to :meth:`Guild.create_forum` to create a :class:`ForumChannel` in the category.

discord/client.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
Tuple,
4343
Type,
4444
TypeVar,
45+
TypedDict,
4546
Union,
4647
overload,
4748
)
@@ -82,7 +83,7 @@
8283
if TYPE_CHECKING:
8384
from types import TracebackType
8485

85-
from typing_extensions import Self
86+
from typing_extensions import Self, Unpack
8687

8788
from .abc import Messageable, PrivateChannel, Snowflake, SnowflakeTime
8889
from .app_commands import Command, ContextMenu
@@ -120,6 +121,28 @@
120121
from .audit_logs import AuditLogEntry
121122
from .poll import PollAnswer
122123
from .subscription import Subscription
124+
from .flags import MemberCacheFlags
125+
126+
class _ClientOptions(TypedDict, total=False):
127+
max_messages: int
128+
proxy: str
129+
proxy_auth: aiohttp.BasicAuth
130+
shard_id: int
131+
shard_count: int
132+
application_id: int
133+
member_cache_flags: MemberCacheFlags
134+
chunk_guilds_at_startup: bool
135+
status: Status
136+
activity: BaseActivity
137+
allowed_mentions: AllowedMentions
138+
heartbeat_timeout: float
139+
guild_ready_timeout: float
140+
assume_unsync_clock: bool
141+
enable_debug_events: bool
142+
enable_raw_presences: bool
143+
http_trace: aiohttp.TraceConfig
144+
max_ratelimit_timeout: float
145+
connector: aiohttp.BaseConnector
123146

124147

125148
# fmt: off
@@ -272,7 +295,7 @@ class Client:
272295
The websocket gateway the client is currently connected to. Could be ``None``.
273296
"""
274297

275-
def __init__(self, *, intents: Intents, **options: Any) -> None:
298+
def __init__(self, *, intents: Intents, **options: Unpack[_ClientOptions]) -> None:
276299
self.loop: asyncio.AbstractEventLoop = _loop
277300
# self.ws is set in the connect method
278301
self.ws: DiscordWebSocket = None # type: ignore

discord/ext/commands/bot.py

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
from .hybrid import hybrid_command, hybrid_group, HybridCommand, HybridGroup
6565

6666
if TYPE_CHECKING:
67-
from typing_extensions import Self
67+
from typing_extensions import Self, Unpack
6868

6969
import importlib.machinery
7070

@@ -80,12 +80,24 @@
8080
MaybeAwaitableFunc,
8181
)
8282
from .core import Command
83-
from .hybrid import CommandCallback, ContextT, P
83+
from .hybrid import CommandCallback, ContextT, P, _HybridCommandDecoratorKwargs, _HybridGroupDecoratorKwargs
84+
from discord.client import _ClientOptions
85+
from discord.shard import _AutoShardedClientOptions
8486

8587
_Prefix = Union[Iterable[str], str]
8688
_PrefixCallable = MaybeAwaitableFunc[[BotT, Message], _Prefix]
8789
PrefixType = Union[_Prefix, _PrefixCallable[BotT]]
8890

91+
class _BotOptions(_ClientOptions, total=False):
92+
owner_id: int
93+
owner_ids: Collection[int]
94+
strip_after_prefix: bool
95+
case_insensitive: bool
96+
97+
class _AutoShardedBotOptions(_AutoShardedClientOptions, _BotOptions):
98+
...
99+
100+
89101
__all__ = (
90102
'when_mentioned',
91103
'when_mentioned_or',
@@ -169,7 +181,7 @@ def __init__(
169181
allowed_contexts: app_commands.AppCommandContext = MISSING,
170182
allowed_installs: app_commands.AppInstallationType = MISSING,
171183
intents: discord.Intents,
172-
**options: Any,
184+
**options: Unpack[_BotOptions],
173185
) -> None:
174186
super().__init__(intents=intents, **options)
175187
self.command_prefix: PrefixType[BotT] = command_prefix # type: ignore
@@ -281,7 +293,7 @@ def hybrid_command(
281293
name: Union[str, app_commands.locale_str] = MISSING,
282294
with_app_command: bool = True,
283295
*args: Any,
284-
**kwargs: Any,
296+
**kwargs: Unpack[_HybridCommandDecoratorKwargs], # type: ignore # name, with_app_command
285297
) -> Callable[[CommandCallback[Any, ContextT, P, T]], HybridCommand[Any, P, T]]:
286298
"""A shortcut decorator that invokes :func:`~discord.ext.commands.hybrid_command` and adds it to
287299
the internal command list via :meth:`add_command`.
@@ -293,8 +305,8 @@ def hybrid_command(
293305
"""
294306

295307
def decorator(func: CommandCallback[Any, ContextT, P, T]):
296-
kwargs.setdefault('parent', self)
297-
result = hybrid_command(name=name, *args, with_app_command=with_app_command, **kwargs)(func)
308+
kwargs.setdefault('parent', self) # type: ignore # parent is not for the user to set
309+
result = hybrid_command(name=name, *args, with_app_command=with_app_command, **kwargs)(func) # type: ignore # name, with_app_command
298310
self.add_command(result)
299311
return result
300312

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

319331
def decorator(func: CommandCallback[Any, ContextT, P, T]):
320-
kwargs.setdefault('parent', self)
321-
result = hybrid_group(name=name, *args, with_app_command=with_app_command, **kwargs)(func)
332+
kwargs.setdefault('parent', self) # type: ignore # parent is not for the user to set
333+
result = hybrid_group(name=name, *args, with_app_command=with_app_command, **kwargs)(func) # type: ignore # name, with_app_command
322334
self.add_command(result)
323335
return result
324336

@@ -1527,4 +1539,18 @@ class AutoShardedBot(BotBase, discord.AutoShardedClient):
15271539
.. versionadded:: 2.0
15281540
"""
15291541

1530-
pass
1542+
if TYPE_CHECKING:
1543+
1544+
def __init__(
1545+
self,
1546+
command_prefix: PrefixType[BotT],
1547+
*,
1548+
help_command: Optional[HelpCommand] = _default,
1549+
tree_cls: Type[app_commands.CommandTree[Any]] = app_commands.CommandTree,
1550+
description: Optional[str] = None,
1551+
allowed_contexts: app_commands.AppCommandContext = MISSING,
1552+
allowed_installs: app_commands.AppInstallationType = MISSING,
1553+
intents: discord.Intents,
1554+
**kwargs: Unpack[_AutoShardedBotOptions],
1555+
) -> None:
1556+
...

discord/ext/commands/cog.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,18 +44,30 @@
4444
Tuple,
4545
TypeVar,
4646
Union,
47+
TypedDict,
4748
)
4849

4950
from ._types import _BaseCommand, BotT
5051

5152
if TYPE_CHECKING:
52-
from typing_extensions import Self
53+
from typing_extensions import Self, Unpack
5354
from discord.abc import Snowflake
5455
from discord._types import ClientT
5556

5657
from .bot import BotBase
5758
from .context import Context
58-
from .core import Command
59+
from .core import Command, _CommandDecoratorKwargs
60+
61+
class _CogKwargs(TypedDict, total=False):
62+
name: str
63+
group_name: Union[str, app_commands.locale_str]
64+
description: str
65+
group_description: Union[str, app_commands.locale_str]
66+
group_nsfw: bool
67+
group_auto_locale_strings: bool
68+
group_extras: Dict[Any, Any]
69+
command_attrs: _CommandDecoratorKwargs
70+
5971

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

172-
def __new__(cls, *args: Any, **kwargs: Any) -> CogMeta:
184+
def __new__(cls, *args: Any, **kwargs: Unpack[_CogKwargs]) -> CogMeta:
173185
name, bases, attrs = args
174186
if any(issubclass(base, app_commands.Group) for base in bases):
175187
raise TypeError(

0 commit comments

Comments
 (0)