@@ -204,7 +204,10 @@ def __init__(
204204 name : str ,
205205 ** kwargs : Unpack [CommandOptions ],
206206 ) -> None :
207+ self ._signature : str | None
208+
207209 self ._name : str = name
210+ self ._parent : Group [Component_T , P ] | None = kwargs .get ("parent" )
208211 self .callback = callback
209212 self ._aliases : list [str ] = kwargs .get ("aliases" , [])
210213 self ._guards : list [Callable [..., bool ] | Callable [..., CoroC ]] = getattr (callback , "__command_guards__" , [])
@@ -215,7 +218,6 @@ def __init__(
215218 self ._injected : Component_T | None = None
216219 self ._error : Callable [[Component_T , CommandErrorPayload ], Coro ] | Callable [[CommandErrorPayload ], Coro ] | None = None
217220 self ._extras : dict [Any , Any ] = kwargs .get ("extras" , {})
218- self ._parent : Group [Component_T , P ] | None = kwargs .get ("parent" )
219221 self ._bypass_global_guards : bool = kwargs .get ("bypass_global_guards" , False )
220222
221223 self ._before_hook : Callable [[Component_T , Context [Any ]], Coro ] | Callable [[Context [Any ]], Coro ] | None = None
@@ -234,6 +236,82 @@ async def __call__(self, context: Context[BotT]) -> Any:
234236 callback = self ._callback (self ._injected , context ) if self ._injected else self ._callback (context ) # type: ignore
235237 return await callback # type: ignore will fix later
236238
239+ def _get_signature (self ) -> None :
240+ params : dict [str , inspect .Parameter ] | None = getattr (self , "_params" , None )
241+ if not params :
242+ self ._signature = None
243+ return
244+
245+ help_sig = ""
246+ for name , param in params .items ():
247+ s = "<{}>"
248+
249+ if param .default is not param .empty :
250+ s = "[{}]"
251+
252+ if param .kind == param .KEYWORD_ONLY :
253+ s = s .format (f"...{ name } " )
254+
255+ elif param .kind == param .VAR_POSITIONAL :
256+ s = s .format (f"{ name } ..." )
257+
258+ elif param .kind == param .POSITIONAL_OR_KEYWORD :
259+ s = s .format (f"{ name } " )
260+
261+ help_sig += f" { s } "
262+
263+ self ._signature = help_sig
264+
265+ @property
266+ def parameters (self ) -> MappingProxyType [str , inspect .Parameter ]:
267+ """Property returning a copy mapping of name to :class:`inspect.Parameter` pair, which are the parameters
268+ of the callback of this command, minus ``self`` (if in a class) and ``ctx``.
269+
270+ Can be used to retrieve the name, annotation, and default value of command parameters.
271+ """
272+ return MappingProxyType (self ._params )
273+
274+ @property
275+ def signature (self ) -> str | None :
276+ """Property returning an easily readable POSIX-like argument signature for the command.
277+
278+ Useful when generating or displaying help.
279+
280+ The format is described below:
281+
282+ - ``<arg>`` is a required argument.
283+ - ``[arg]`` is an optional argument.
284+ - ``...arg`` is a consume-rest argument.
285+ - ``arg...`` is an argument list.
286+
287+ Example
288+ -------
289+
290+ .. code:: python3
291+
292+ @commands.command()
293+ async def test(ctx: commands.Context, hello: str, world: int) -> None: ...
294+ ...
295+
296+ print(test.signature) # <hello> <world>
297+
298+
299+ @commands.command()
300+ async def test(ctx: commands.Context, arg: str, *, other: str | None = None) -> None: ...
301+ ...
302+
303+ print(test.signature) # <arg> [...other]
304+
305+
306+ @commands.command()
307+ async def test(ctx: commands.Context, arg: str, other: str | None = None, *args: str | None = None) -> None: ...
308+ ...
309+
310+ print(test.signature) # <arg> [other] [args...]
311+
312+ """
313+ return self ._signature
314+
237315 @property
238316 def help (self ) -> str :
239317 """Property returning a :class:`str` which is the docstring associated with the command callback.
@@ -351,6 +429,7 @@ def callback(
351429 globalns = {}
352430
353431 self ._params : dict [str , inspect .Parameter ] = get_signature_parameters (func , globalns )
432+ self ._get_signature ()
354433
355434 def _convert_literal_type (
356435 self , context : Context [BotT ], param : inspect .Parameter , args : tuple [Any , ...], * , raw : str | None
0 commit comments