python-fire icon indicating copy to clipboard operation
python-fire copied to clipboard

--help doesn't display correctly when using sub-groups;

Open washad opened this issue 3 years ago • 1 comments

Hey, great job, love the tool !!!!

When creating command groups using classes, --help isn't correctly displaying.

Consider this example

import fire
class GroupBase:
    def __init__(self, verbose: bool):
        self.verbose = verbose
class Group1(GroupBase):
    def command1(self):
        """This command seen by group 1 only"""
        print(f"I am a group1 command with verbosity {self.verbose}")
class Group2(GroupBase):
    def command2(self):
        """This command will be seen by group 2."""
        print(f"I am a group2 command with verbosity {self.verbose}")
class Base:
    def __init__(self, verbose: bool = False):
        self.verbose = verbose
        self.group1 = Group1(verbose)
        self.group2 = Group2(verbose)
    def common1(self):
        """This command will be seen at the base level."""
        print(f"I am a common command with verbosity {self.verbose}")
def main():
    fire.Fire(Base)
if __name__ == '__main__':
    main()

if I type python main.py, I get the correct help file; Note the existence of the two groups (group1, group2). (though help for verbose isn't correct.)

NAME
    main.py

SYNOPSIS
    main.py - GROUP | COMMAND | VALUE

GROUPS
    GROUP is one of the following:

     group1

     group2

COMMANDS
    COMMAND is one of the following:

     common1
       This command will be seen at the base level.

VALUES
    VALUE is one of the following:

     verbose

If, instead, I use --help python main.py --help, groups are not shown.

NAME
    main.py

SYNOPSIS
    main.py <flags>

FLAGS
    --verbose=VERBOSE
        Type: bool
        Default: False

washad avatar Mar 02 '21 21:03 washad

I ran into this same issue. Setting subcommands/groups as fields on the base class doesn't work too well. Moving the group classes into the base class helps, i.e.

class Base:
    class Group1:
        def command1(self):
                pass

I found it easier to just have a commands dictionary and do everything functionally. I.e.

import fire

def command1(verbose):
    """This command seen by group 1 only"""
    print(f"I am a group1 command with verbosity {verbose}")

def command2(verbose):
    """This command will be seen by group 2."""
    print(f"I am a group2 command with verbosity {verbose}")

def common1(verbose):
    """This command will be seen at the base level."""
    print(f"I am a common command with verbosity {verbose}")

def main():
    cli_map = {
        "common1": common1,
        "group1": {"command1": command1},
        "group2": {"command2": command2},
    }
    fire.Fire(cli_map)

if __name__ == "__main__":
    main()

JasonAtallah avatar Mar 11 '21 21:03 JasonAtallah