44with automatic argument parsing and completion.
55"""
66
7- from copy import copy
87import sys
98from argparse import ArgumentParser , Namespace , _SubParsersAction
9+ from copy import copy
1010from functools import partial , update_wrapper
1111from inspect import Parameter , signature
1212from types import MethodType
2626 overload ,
2727)
2828
29- from typing_extensions import ParamSpec
3029from rich_argparse import RichHelpFormatter
30+ from typing_extensions import ParamSpec , Concatenate , Self
3131
3232from .argument import build_parser
3333from .completer import ArgparseCompleter
3838
3939
4040_P = ParamSpec ("_P" )
41- _P_Subcmd = ParamSpec ("_P_Subcmd" )
41+ _P_Method = ParamSpec ("_P_Method" )
42+ _P_Subcmd = ParamSpec ("_P_Subcmd" )
4243_T = TypeVar ("_T" )
4344_T_Subcmd = TypeVar ("_T_Subcmd" )
4445
@@ -51,9 +52,10 @@ class Command(Generic[_P, _T]):
5152 - Command metadata (name, hidden status, disabled status)
5253 - Argument completion support
5354 - Method binding for instance commands
55+ - Subcommand management
5456
55- The Command class is typically created through the @command decorator rather
56- than being instantiated directly.
57+ The Command class is typically created through the @auto_argument decorator
58+ rather than being instantiated directly.
5759 """
5860
5961 def __init__ (
@@ -134,6 +136,26 @@ def add_subcommand(
134136 add_help : bool = True ,
135137 ** kwds : Any ,
136138 ) -> Union [Callable [[Callable [_P_Subcmd , _T_Subcmd ]], "Command[_P_Subcmd, _T_Subcmd]" ], "Command[_P_Subcmd, _T_Subcmd]" ]:
139+ """Add a subcommand to this command.
140+
141+ This method can be used as a decorator or directly with a function.
142+ It creates a nested command structure where the current command acts as a parent.
143+
144+ :param name: Name of the subcommand
145+ :type name: str
146+ :param func: The function to wrap as a subcommand (if provided directly)
147+ :type func: Optional[Callable[_P_Subcmd, _T_Subcmd]]
148+ :param help: Help text for the subcommand
149+ :type help: Optional[str]
150+ :param aliases: Aliases for the subcommand
151+ :type aliases: Sequence[str]
152+ :param add_help: Whether to add help for the subcommand
153+ :type add极_help: bool
154+ :param kwds: Additional keyword arguments for the Command constructor
155+ :type kwds: Any
156+ :return: Either a decorator function or a Command instance
157+ :rtype: Union[Callable[[Callable[_P_Subcmd, _T_Subcmd]], Command[_P_Subcmd, _T_Subcmd]], Command[_P_Subcmd, _T_Subcmd]]
158+ """
137159 subparser_action = self ._ensure_subparsers ()
138160 def inner (inner : Callable [_P_Subcmd , _T_Subcmd ]) -> "Command[_P_Subcmd, _T_Subcmd]" :
139161 return cast (Type [Command ], self .__class__ )(
@@ -158,11 +180,20 @@ def inner(inner: Callable[_P_Subcmd, _T_Subcmd]) -> "Command[_P_Subcmd, _T_Subcm
158180 return inner (func )
159181
160182 def completer_getter (self , func : CompleterGetterFunc ) -> CompleterGetterFunc :
183+ """Decorator to set a custom completer getter function for this command.
184+
185+ The completer getter function should accept a BaseCmd instance and return a Completer.
186+
187+ :param func: The completer getter function
188+ :type func: CompleterGetterFunc
189+ :return: The same function (for decorator chaining)
190+ :rtype: CompleterGetterFunc
191+ """
161192 self ._completer_getter = func
162193 return func
163194
164195 def invoke_from_argv (self , cmd : "BaseCmd" , argv : List [str ], * , parser : Optional [ArgumentParser ] = None ) -> Any :
165- """Invoke the command with parsed arguments.
196+ """Invoke the command with parsed arguments from a list of argv strings .
166197
167198 This method parses command-line arguments and invokes the command function.
168199 It handles redirecting stdin/stdout during argument parsing.
@@ -171,6 +202,8 @@ def invoke_from_argv(self, cmd: "BaseCmd", argv: List[str], *, parser: Optional[
171202 :type cmd: "BaseCmd"
172203 :param argv: List of argument strings to parse
173204 :type argv: List[str]
205+ :param parser: Optional ArgumentParser to use (default: self.parser)
206+ :type parser: Optional[ArgumentParser]
174207 :return: The result of the wrapped function
175208 :rtype: Any
176209 """
@@ -190,7 +223,19 @@ def invoke_from_argv(self, cmd: "BaseCmd", argv: List[str], *, parser: Optional[
190223 sys .stdout = old_stdout
191224 sys .stderr = old_stderr
192225 return self .invoke_from_ns (cmd , ns )
226+
193227 def invoke_from_ns (self , cmd : "BaseCmd" , ns : Namespace ) -> Any :
228+ """Invoke the command from a parsed namespace object.
229+
230+ This method handles nested command invocation by traversing the command chain.
231+
232+ :param cmd: The BaseCmd instance this command belongs to
233+ :type cmd: "BaseCmd"
234+ :param ns: The parsed argument namespace
235+ :type ns: Namespace
236+ :return: The result of the wrapped function
237+ :rtype: Any
238+ """
194239 cmd_ins = getattr (ns , "__cmd_ins__" , self )
195240 cmd_chain = [cmd_ins ]
196241 while cmd_ins ._parent is not None and cmd_ins is not self :
@@ -248,14 +293,14 @@ def _ensure_subparsers(self) -> _SubParsersAction:
248293 return self .parser .add_subparsers (metavar = 'SUBCOMMAND' )
249294
250295 @overload
251- def __get__ (self , instance : None , owner : Optional [type ]) -> "Command[_P, _T]" :
252- ...
296+ def __get__ (self , instance : None , owner : Optional [type ]) -> Self : ...
253297
254298 @overload
255- def __get__ (self , instance : object , owner : Optional [type ]) -> Callable [_P , _T ]:
256- ...
299+ def __get__ (
300+ self : "Command[Concatenate[Any, _P_Method], _T]" , instance : object , owner : Optional [type ]
301+ ) -> Callable [_P_Method , _T ]: ...
257302
258- def __get__ (self , instance : Optional [object ], owner : Optional [type ]) -> Union [ "Command[_P, _T]" , Callable [_P , _T ] ]:
303+ def __get__ (self , instance : Optional [object ], owner : Optional [type ]) -> Callable [... , _T ]:
259304 """Descriptor protocol implementation for method binding.
260305
261306 This allows Command instances to behave like methods when accessed
0 commit comments