@@ -413,6 +413,43 @@ def __getattr__(self, attr):
413413 return getattr (self .parser , attr )
414414
415415
416+ class GroupReference :
417+ """
418+ Simple class to hold tools command group names comparable to how
419+ they would be invoked using the CLI.
420+
421+ For example, tools vm create is stored as ("tools", "vm", "create")
422+ """
423+
424+ _instance : GroupReference | None = None
425+ _commands : list [str ]
426+
427+ def __new__ (cls ):
428+ """
429+ Method that instantiates a singleton class and returns it.
430+ """
431+ if cls ._instance is None :
432+ instance = super ().__new__ (cls )
433+ instance ._commands = {}
434+ cls ._instance = instance
435+ return cls ._instance
436+
437+ @classmethod
438+ def add_command (cls , cli_name : tuple [str ], group : CommandGroup ) -> None :
439+ """
440+ Add a tools command.
441+ """
442+ instance = cls ()
443+ if cli_name not in instance ._commands :
444+ instance ._commands [cli_name ] = group
445+
446+ def __getitem__ (self , item ):
447+ """
448+ Propogate getting a command parser to the underlying dict.
449+ """
450+ return self ._commands [item ]
451+
452+
416453class CommandGroup :
417454 """
418455 Command group which holds the available tool functions.
@@ -424,6 +461,16 @@ def __init__(self, name, help, description=None, parent=None, venv_config=None):
424461 description = help
425462 if parent is None :
426463 parent = Parser ()
464+ GroupReference .add_command ((name ,), self )
465+ # We can also pass a string or list of strings that specify the parent commands.
466+ # This should help avoid circular imports
467+ if isinstance (parent , str ):
468+ parent = [parent ]
469+ if isinstance (parent , list ):
470+ # NOTE: This means ordering of imports is important, but better than risking circular imports
471+ GroupReference .add_command (tuple (parent + [name ]), self )
472+ parent = GroupReference ()[tuple (parent )]
473+
427474 self .venv_config = venv_config or {}
428475 self .parser = parent .subparsers .add_parser (
429476 name .replace ("_" , "-" ),
0 commit comments