Skip to content

Commit 6e65959

Browse files
authored
Merge core/typing (#432)
1 parent eb981d3 commit 6e65959

27 files changed

+987
-497
lines changed

.github/workflows/docs.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ jobs:
77
runs-on: ubuntu-latest
88
strategy:
99
matrix:
10-
python-version: [ 3.8 ]
10+
python-version: [ '3.10' ]
1111
steps:
1212
- uses: actions/checkout@v2
1313
- name: Set up Python ${{ matrix.python-version }}
@@ -17,7 +17,7 @@ jobs:
1717
- name: Install dependencies
1818
run: |
1919
python -m pip install -U pip
20-
pip install -U sphinx sphinxcontrib-trio aiohttp sphinxcontrib-websupport myst-parser
20+
pip install -U sphinx sphinxcontrib-trio aiohttp sphinxcontrib-websupport myst-parser typing-extensions
2121
- name: Compile to html
2222
run: |
2323
cd docs

discord/asset.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,11 +268,11 @@ def __str__(self) -> str:
268268
def __len__(self) -> int:
269269
return len(self._url)
270270

271-
def __repr__(self):
271+
def __repr__(self) -> str:
272272
shorten = self._url.replace(self.BASE, '')
273273
return f'<Asset url={shorten!r}>'
274274

275-
def __eq__(self, other):
275+
def __eq__(self, other) -> bool:
276276
return isinstance(other, Asset) and self._url == other._url
277277

278278
def __hash__(self):

discord/bot.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
Type,
4141
TypeVar,
4242
Union,
43+
Type,
4344
)
4445

4546
from .client import Client

discord/commands/_types.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
from typing import Callable, TYPE_CHECKING, Union, Coroutine, Any, TypeVar
2+
3+
if TYPE_CHECKING:
4+
from .. import Cog, ApplicationContext
5+
6+
T = TypeVar('T')
7+
8+
Coro = Coroutine[Any, Any, T]
9+
MaybeCoro = Union[T, Coro[T]]
10+
CoroFunc = Callable[..., Coro[Any]]
11+
12+
Check = Union[Callable[["Cog", "ApplicationContext[Any]"], MaybeCoro[bool]],
13+
Callable[["ApplicationContext[Any]"], MaybeCoro[bool]]]
14+
Hook = Union[Callable[["Cog", "ApplicationContext[Any]"], Coro[Any]], Callable[["ApplicationContext[Any]"], Coro[Any]]]
15+
Error = Union[Callable[["Cog", "ApplicationContext[Any]", "CommandError"], Coro[Any]],
16+
Callable[["ApplicationContext[Any]", "CommandError"], Coro[Any]]]

discord/commands/context.py

Lines changed: 82 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,26 @@
2424
"""
2525
from __future__ import annotations
2626

27-
from typing import TYPE_CHECKING, Optional, TypeVar, Union
27+
from typing import TYPE_CHECKING, Optional, Union, TypeVar, Generic, Callable, List, Any, Dict
2828

29-
import discord.abc
29+
import discord.utils
3030

3131
if TYPE_CHECKING:
32-
from typing_extensions import ParamSpec
33-
34-
import discord
35-
from discord import Bot
36-
from discord.state import ConnectionState
37-
38-
from .core import ApplicationCommand, Option
32+
from . import ApplicationCommand, Option
3933
from ..cog import Cog
40-
from ..webhook import WebhookMessage
41-
from typing import Callable
34+
from ..embeds import Embed
35+
from ..file import File
36+
from ..guild import Guild
37+
from ..interactions import Interaction, InteractionChannel, InteractionResponse, InteractionMessage
38+
from ..member import Member
39+
from ..mentions import AllowedMentions
40+
from ..message import Message
41+
from ..state import ConnectionState
42+
from ..user import User
43+
from ..ui import View
44+
from ..voice_client import VoiceProtocol
45+
from ..webhook import Webhook, WebhookMessage
46+
from typing_extensions import ParamSpec
4247

4348
from ..guild import Guild
4449
from ..interactions import Interaction, InteractionResponse
@@ -58,7 +63,18 @@
5863
__all__ = ("ApplicationContext", "AutocompleteContext")
5964

6065

61-
class ApplicationContext(discord.abc.Messageable):
66+
MISSING: Any = discord.utils.MISSING
67+
68+
T = TypeVar("T")
69+
BotT = TypeVar("BotT", bound="Union[discord.Bot, discord.AutoShardedBot]")
70+
CogT = TypeVar("CogT", bound="Cog")
71+
72+
if TYPE_CHECKING:
73+
P = ParamSpec('P')
74+
else:
75+
P = TypeVar('P')
76+
77+
class ApplicationContext(discord.abc.Messageable, Generic[BotT]):
6278
"""Represents a Discord application command interaction context.
6379
6480
This class is not created manually and is instead passed to application
@@ -76,9 +92,9 @@ class ApplicationContext(discord.abc.Messageable):
7692
The command that this context belongs to.
7793
"""
7894

79-
def __init__(self, bot: Bot, interaction: Interaction):
80-
self.bot = bot
81-
self.interaction = interaction
95+
def __init__(self, bot: BotT, interaction: Interaction) -> None:
96+
self.bot: BotT = bot
97+
self.interaction: Interaction = interaction
8298

8399
# below attributes will be set after initialization
84100
self.command: ApplicationCommand = None # type: ignore
@@ -88,7 +104,7 @@ def __init__(self, bot: Bot, interaction: Interaction):
88104

89105
self._state: ConnectionState = self.interaction._state
90106

91-
async def _get_channel(self) -> discord.abc.Messageable:
107+
async def _get_channel(self) -> Optional[InteractionChannel]:
92108
return self.channel
93109

94110
async def invoke(self, command: ApplicationCommand[CogT, P, T], /, *args: P.args, **kwargs: P.kwargs) -> T:
@@ -118,7 +134,7 @@ async def invoke(self, command: ApplicationCommand[CogT, P, T], /, *args: P.args
118134
return await command(self, *args, **kwargs)
119135

120136
@cached_property
121-
def channel(self):
137+
def channel(self) -> Optional[InteractionChannel]:
122138
return self.interaction.channel
123139

124140
@cached_property
@@ -133,14 +149,6 @@ def guild(self) -> Optional[Guild]:
133149
def guild_id(self) -> Optional[int]:
134150
return self.interaction.guild_id
135151

136-
@cached_property
137-
def locale(self) -> Optional[str]:
138-
return self.interaction.locale
139-
140-
@cached_property
141-
def guild_locale(self) -> Optional[str]:
142-
return self.interaction.guild_locale
143-
144152
@cached_property
145153
def me(self) -> Union[Member, User]:
146154
return self.guild.me if self.guild is not None else self.bot.user
@@ -168,6 +176,14 @@ def voice_client(self):
168176
def response(self) -> InteractionResponse:
169177
return self.interaction.response
170178

179+
@property
180+
def cog(self) -> Optional[Cog]:
181+
"""Optional[:class:`.Cog`]: Returns the cog associated with this context's command. ``None`` if it does not exist."""
182+
if self.command is None:
183+
return None
184+
185+
return self.command.cog
186+
171187
@property
172188
def respond(self) -> Callable[..., Union[Interaction, WebhookMessage]]:
173189
"""Callable[..., Union[:class:`~.Interaction`, :class:`~.Webhook`]]: Sends either a response
@@ -195,33 +211,42 @@ def send_followup(self):
195211
f"Interaction was not yet issued a response. Try using {type(self).__name__}.respond() first."
196212
)
197213

198-
@property
199-
def defer(self):
200-
return self.interaction.response.defer
214+
@discord.utils.copy_doc(InteractionResponse.defer)
215+
async def defer(self, *, ephemeral: bool = False) -> None:
216+
return await self.interaction.response.defer(ephemeral=ephemeral)
201217

202218
@property
203-
def followup(self):
219+
def followup(self) -> Webhook:
204220
return self.interaction.followup
205221

206-
async def delete(self):
222+
async def delete(self) -> None:
207223
"""Calls :attr:`~discord.commands.ApplicationContext.respond`.
208224
If the response is done, then calls :attr:`~discord.commands.ApplicationContext.respond` first."""
209225
if not self.response.is_done():
210226
await self.defer()
211227

212228
return await self.interaction.delete_original_message()
213229

214-
@property
215-
def edit(self):
216-
return self.interaction.edit_original_message
217-
218-
@property
219-
def cog(self) -> Optional[Cog]:
220-
"""Optional[:class:`.Cog`]: Returns the cog associated with this context's command. ``None`` if it does not exist."""
221-
if self.command is None:
222-
return None
223-
224-
return self.command.cog
230+
async def edit(
231+
self,
232+
*,
233+
content: Optional[str] = MISSING,
234+
embeds: List[Embed] = MISSING,
235+
embed: Optional[Embed] = MISSING,
236+
file: File = MISSING,
237+
files: List[File] = MISSING,
238+
view: Optional[View] = MISSING,
239+
allowed_mentions: Optional[AllowedMentions] = None,
240+
) -> InteractionMessage:
241+
return await self.interaction.edit_original_message(
242+
content=content,
243+
embeds=embeds,
244+
embed=embed,
245+
file=file,
246+
files=files,
247+
view=view,
248+
allowed_mentions=allowed_mentions,
249+
)
225250

226251

227252
class AutocompleteContext:
@@ -248,18 +273,24 @@ class AutocompleteContext:
248273
"""
249274

250275
__slots__ = ("bot", "interaction", "command", "focused", "value", "options")
251-
252-
def __init__(self, bot: Bot, interaction: Interaction) -> None:
253-
self.bot = bot
254-
self.interaction = interaction
255-
256-
self.command: ApplicationCommand = None # type: ignore
257-
self.focused: Option = None # type: ignore
258-
self.value: str = None # type: ignore
259-
self.options: dict = None # type: ignore
276+
277+
def __init__(
278+
self,
279+
interaction: Interaction,
280+
*,
281+
command: ApplicationCommand,
282+
focused: Option,
283+
value: str,
284+
options: Dict[str, Any],
285+
) -> None:
286+
self.interaction: Interaction = interaction
287+
self.command: ApplicationCommand = command
288+
self.focused: Option = focused
289+
self.value: str = value
290+
self.options: Dict[str, Any] = options
260291

261292
@property
262-
def cog(self) -> Optional[Cog]:
293+
def cog(self) -> Optional[CogT]:
263294
"""Optional[:class:`.Cog`]: Returns the cog associated with this context's command. ``None`` if it does not exist."""
264295
if self.command is None:
265296
return None

0 commit comments

Comments
 (0)