@@ -210,6 +210,19 @@ def __init__(self, cli_ctx=None):
210210 self .cmd_to_loader_map = {}
211211 self .loaders = []
212212
213+ def _create_stub_commands_for_completion (self , command_names ):
214+ """Create stub commands for top-level tab completion optimization.
215+
216+ Stub commands allow argcomplete to parse command names without loading modules.
217+
218+ :param command_names: List of command names to create stubs for
219+ """
220+ from azure .cli .core .commands import AzCliCommand
221+ for cmd_name in command_names :
222+ if cmd_name not in self .command_table :
223+ # Create stub with no-op handler - never invoked during completion
224+ self .command_table [cmd_name ] = AzCliCommand (self , cmd_name , lambda : None )
225+
213226 def _update_command_definitions (self ):
214227 for cmd_name in self .command_table :
215228 loaders = self .cmd_to_loader_map [cmd_name ]
@@ -436,17 +449,9 @@ def _get_extension_suppressions(mod_loaders):
436449 index_result = command_index .get (args )
437450 if index_result :
438451 index_modules , index_extensions = index_result
439- # Special case for top-level completion - create minimal command groups
452+
440453 if index_modules == TOP_LEVEL_COMPLETION_MARKER :
441- from azure .cli .core .commands import AzCliCommand
442- # index_extensions contains the command names, not extensions
443- for cmd_name in index_extensions :
444- # Create a minimal command entry for tab completion
445- # This allows argparse to see the command without loading the module
446- if cmd_name not in self .command_table :
447- self .command_table [cmd_name ] = AzCliCommand (
448- self , cmd_name , lambda : None
449- )
454+ self ._create_stub_commands_for_completion (index_extensions )
450455 return self .command_table
451456
452457 # Always load modules and extensions, because some of them (like those in
@@ -500,7 +505,6 @@ def _get_extension_suppressions(mod_loaders):
500505 else :
501506 logger .debug ("No module found from index for '%s'" , args )
502507
503- # No module found from the index. Load all command modules and extensions
504508 logger .debug ("Loading all modules and extensions" )
505509 _update_command_table_from_modules (args )
506510
@@ -596,6 +600,18 @@ def __init__(self, cli_ctx=None):
596600 self .cloud_profile = cli_ctx .cloud .profile
597601 self .cli_ctx = cli_ctx
598602
603+ def _get_top_level_completion_commands (self ):
604+ """Get all command names for top-level completion optimization.
605+
606+ Returns marker and command list for creating stub commands without module loading.
607+
608+ :return: tuple of (TOP_LEVEL_COMPLETION_MARKER, list of command names)
609+ """
610+ index = self .INDEX [self ._COMMAND_INDEX ]
611+ all_commands = list (index .keys ())
612+ logger .debug ("Top-level completion: %d commands available" , len (all_commands ))
613+ return TOP_LEVEL_COMPLETION_MARKER , all_commands
614+
599615 def get (self , args ):
600616 """Get the corresponding module and extension list of a command.
601617
@@ -617,11 +633,7 @@ def get(self, args):
617633 if not args or args [0 ].startswith ('-' ):
618634 # For top-level completion (az [tab])
619635 if not args and self .cli_ctx .data .get ('completer_active' ):
620- # Return a special marker so we know to skip module loading for top-level completion
621- index = self .INDEX [self ._COMMAND_INDEX ]
622- all_commands = list (index .keys ())
623- logger .debug ("Top-level completion: %d commands available" , len (all_commands ))
624- return TOP_LEVEL_COMPLETION_MARKER , all_commands # special marker, command list
636+ return self ._get_top_level_completion_commands ()
625637 return None
626638
627639 # Get the top-level command, like `network` in `network vnet create -h`
0 commit comments