@@ -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,73 @@ 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 signature (self ) -> str | None :
267+ """Property returning an easily readable POSIX-like argument signature for the command.
268+
269+ Useful when generating or displaying help.
270+
271+ The format is described below:
272+
273+ - ``<arg>`` is a required argument.
274+ - ``[arg]`` is an optional argument.
275+ - ``...arg`` is a consume-rest argument.
276+ - ``arg...`` is an argument list.
277+
278+ Example
279+ -------
280+
281+ .. code:: python3
282+
283+ @commands.command()
284+ async def test(ctx: commands.Context, hello: str, world: int) -> None: ...
285+ ...
286+
287+ print(test.signature) # <hello> <world>
288+
289+
290+ @commands.command()
291+ async def test(ctx: commands.Context, arg: str, *, other: str | None = None) -> None: ...
292+ ...
293+
294+ print(test.signature) # <arg> [...other]
295+
296+
297+ @commands.command()
298+ async def test(ctx: commands.Context, arg: str, other: str | None = None, *args: str | None = None) -> None: ...
299+ ...
300+
301+ print(test.signature) # <arg> [other] [args...]
302+
303+ """
304+ return self ._signature
305+
237306 @property
238307 def help (self ) -> str :
239308 """Property returning a :class:`str` which is the docstring associated with the command callback.
@@ -351,6 +420,7 @@ def callback(
351420 globalns = {}
352421
353422 self ._params : dict [str , inspect .Parameter ] = get_signature_parameters (func , globalns )
423+ self ._get_signature ()
354424
355425 def _convert_literal_type (
356426 self , context : Context [BotT ], param : inspect .Parameter , args : tuple [Any , ...], * , raw : str | None
0 commit comments