@@ -259,22 +259,6 @@ def __init__(self, completekey: str = 'tab', stdin=None, stdout=None, *,
259
259
multiline_commands = multiline_commands ,
260
260
shortcuts = shortcuts )
261
261
262
- # Load modular commands
263
- self ._installed_command_sets = [] # type: List[CommandSet]
264
- self ._cmd_to_command_sets = {} # type: Dict[str, CommandSet]
265
- if command_sets :
266
- for command_set in command_sets :
267
- self .register_command_set (command_set )
268
-
269
- if auto_load_commands :
270
- self ._autoload_commands ()
271
-
272
- # Verify commands don't have invalid names (like starting with a shortcut)
273
- for cur_cmd in self .get_all_commands ():
274
- valid , errmsg = self .statement_parser .is_valid_command (cur_cmd )
275
- if not valid :
276
- raise ValueError ("Invalid command name {!r}: {}" .format (cur_cmd , errmsg ))
277
-
278
262
# Stores results from the last command run to enable usage of results in a Python script or interactive console
279
263
# Built-in commands don't make use of this. It is purely there for user-defined commands and convenience.
280
264
self .last_result = None
@@ -412,6 +396,28 @@ def __init__(self, completekey: str = 'tab', stdin=None, stdout=None, *,
412
396
# If False, then complete() will sort the matches using self.default_sort_key before they are displayed.
413
397
self .matches_sorted = False
414
398
399
+ ############################################################################################################
400
+ # The following code block loads CommandSets, verifies command names, and registers subcommands.
401
+ # This block should appear after all attributes have been created since the registration code
402
+ # depends on them and it's possible a module's on_register() method may need to access some.
403
+ ############################################################################################################
404
+ # Load modular commands
405
+ self ._installed_command_sets = [] # type: List[CommandSet]
406
+ self ._cmd_to_command_sets = {} # type: Dict[str, CommandSet]
407
+ if command_sets :
408
+ for command_set in command_sets :
409
+ self .register_command_set (command_set )
410
+
411
+ if auto_load_commands :
412
+ self ._autoload_commands ()
413
+
414
+ # Verify commands don't have invalid names (like starting with a shortcut)
415
+ for cur_cmd in self .get_all_commands ():
416
+ valid , errmsg = self .statement_parser .is_valid_command (cur_cmd )
417
+ if not valid :
418
+ raise ValueError ("Invalid command name {!r}: {}" .format (cur_cmd , errmsg ))
419
+
420
+ # Add functions decorated to be subcommands
415
421
self ._register_subcommands (self )
416
422
417
423
def find_commandsets (self , commandset_type : Type [CommandSet ], * , subclass_match : bool = False ) -> List [CommandSet ]:
@@ -631,10 +637,14 @@ def _register_subcommands(self, cmdset: Union[CommandSet, 'Cmd']) -> None:
631
637
632
638
# iterate through all matching methods
633
639
for method_name , method in methods :
634
- subcommand_name = getattr (method , constants .SUBCMD_ATTR_NAME )
640
+ subcommand_name = getattr (method , constants .SUBCMD_ATTR_NAME ) # type: str
635
641
full_command_name = getattr (method , constants .SUBCMD_ATTR_COMMAND ) # type: str
636
642
subcmd_parser = getattr (method , constants .CMD_ATTR_ARGPARSER )
637
643
644
+ subcommand_valid , errmsg = self .statement_parser .is_valid_command (subcommand_name , is_subcommand = True )
645
+ if not subcommand_valid :
646
+ raise CommandSetRegistrationError ('Subcommand {} is not valid: {}' .format (str (subcommand_name ), errmsg ))
647
+
638
648
command_tokens = full_command_name .split ()
639
649
command_name = command_tokens [0 ]
640
650
subcommand_names = command_tokens [1 :]
0 commit comments