Skip to content

Commit 04037d1

Browse files
committed
Implement ApplicationContext.invoke
1 parent 51dd856 commit 04037d1

File tree

2 files changed

+51
-4
lines changed

2 files changed

+51
-4
lines changed

discord/commands/commands.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@
3131
import re
3232
import types
3333
from collections import OrderedDict
34-
from typing import Any, Callable, Dict, List, Optional, Type, Union, TYPE_CHECKING
34+
from typing import Any, Callable, Dict, Generic, List, Optional, Type, TypeVar, Union, TYPE_CHECKING
35+
from typing_extensions import ParamSpec
3536

3637
from .context import ApplicationContext, AutocompleteContext
3738
from .errors import ApplicationCommandError, CheckFailure, ApplicationCommandInvokeError
@@ -61,9 +62,18 @@
6162
"MessageCommand",
6263
)
6364

64-
if TYPE_CHECKING:
65+
if TYPE_CHECKING:
66+
from ..cog import Cog
6567
from ..interactions import Interaction
6668

69+
T = TypeVar('T')
70+
CogT = TypeVar('CogT', bound='Cog')
71+
72+
if TYPE_CHECKING:
73+
P = ParamSpec('P')
74+
else:
75+
P = TypeVar('P')
76+
6777
def wrap_callback(coro):
6878
@functools.wraps(coro)
6979
async def wrapped(*args, **kwargs):
@@ -97,7 +107,7 @@ async def wrapped(arg):
97107
class _BaseCommand:
98108
__slots__ = ()
99109

100-
class ApplicationCommand(_BaseCommand):
110+
class ApplicationCommand(_BaseCommand, Generic[CogT, P, T]):
101111
cog = None
102112

103113
def __repr__(self):

discord/commands/context.py

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,13 @@
2424
"""
2525
from __future__ import annotations
2626

27-
from typing import TYPE_CHECKING, Optional, Union
27+
from typing import Callable, TYPE_CHECKING, Optional, TypeVar, Union
2828

2929
import discord.abc
3030

3131
if TYPE_CHECKING:
32+
from typing_extensions import ParamSpec
33+
3234
import discord
3335
from discord import Bot
3436
from discord.state import ConnectionState
@@ -42,6 +44,15 @@
4244
from ..message import Message
4345
from ..user import User
4446
from ..utils import cached_property
47+
from ..webhook import Webhook
48+
49+
T = TypeVar('T')
50+
CogT = TypeVar('CogT', bound="Cog")
51+
52+
if TYPE_CHECKING:
53+
P = ParamSpec('P')
54+
else:
55+
P = TypeVar('P')
4556

4657
__all__ = (
4758
"ApplicationContext",
@@ -81,6 +92,32 @@ def __init__(self, bot: Bot, interaction: Interaction):
8192
async def _get_channel(self) -> discord.abc.Messageable:
8293
return self.channel
8394

95+
async def invoke(self, command: ApplicationCommand[CogT, P, T], /, *args: P.args, **kwargs: P.kwargs) -> T:
96+
r"""|coro|
97+
Calls a command with the arguments given.
98+
This is useful if you want to just call the callback that a
99+
:class:`.ApplicationCommand` holds internally.
100+
.. note::
101+
This does not handle converters, checks, cooldowns, pre-invoke,
102+
or after-invoke hooks in any matter. It calls the internal callback
103+
directly as-if it was a regular function.
104+
You must take care in passing the proper arguments when
105+
using this function.
106+
Parameters
107+
-----------
108+
command: :class:`.ApplicationCommand`
109+
The command that is going to be called.
110+
\*args
111+
The arguments to use.
112+
\*\*kwargs
113+
The keyword arguments to use.
114+
Raises
115+
-------
116+
TypeError
117+
The command argument to invoke is missing.
118+
"""
119+
return await command(self, *args, **kwargs)
120+
84121
@cached_property
85122
def channel(self):
86123
return self.interaction.channel

0 commit comments

Comments
 (0)