google / python-fire

Python Fire is a library for automatically generating command line interfaces (CLIs) from absolutely any Python object.
Other
26.98k stars 1.44k forks source link

Usage message is displayed when not desired. #441

Open JimBiardClimateAI opened 1 year ago

JimBiardClimateAI commented 1 year ago

When I build a class with methods that can be chained (they return self), I find that the "commands" help message is written out even when I provide commands with proper arguments and the commands are executed. Here is the code

from __future__ import annotations
from fire import Fire

class Foo:
    def act(self, x: int) -> Foo:
        """
        Act for some number of minutes.
        Parameters
        ----------
        x : int
            The number of minutes to act.
        """

        print("act", x, "minute(s)")
        return self

    def rest(self, x: int, y: str = "hours") -> Foo:
        """
        Rest for a while.
        Parameters
        ----------
        x : int
            The time to rest.
        y : str
            The units of x. The default is hours.
        """

        print("rest", x, y)
        return self

if __name__ == "__main__":
    Fire(Foo)

If I run this as python fire_bug.py, I get the help output I expect, which is

NAME
    fire_bug.py act 1

SYNOPSIS
    fire_bug.py act 1 COMMAND

COMMANDS
    COMMAND is one of the following:

     act
       Act for some number of minutes.

     rest
       Rest for a while.

If I run this as python fire_bug.py act 1, I unexpectedly get the help output

NAME
    fire_bug.py act 1

SYNOPSIS
    fire_bug.py act 1 COMMAND

COMMANDS
    COMMAND is one of the following:

     act
       Act for some number of minutes.

     rest
       Rest for a while.

followed by the output I expect, which is

act 1 minute(s)

If run this as python fire_bug.py act 1 rest 9, I again unexpectedly get the help output

NAME
    fire_bug.py act 1 rest 9

SYNOPSIS
    fire_bug.py act 1 rest 9 - COMMAND

COMMANDS
    COMMAND is one of the following:

     act
       Act for some number of minutes.

     rest
       Rest for a while.

followed by the output I expect, which is

act 1 minute(s)
rest 9 hours

If I add a __str__ method to the class that returns "\b", I don't get the unexpected messages, but I also don't get a help message if I run python fire_bug.py.

As a general observation, running python fire_bug.py --help does not produce useful output. The output is

NAME
    fire_bug.py

SYNOPSIS
    fire_bug.py -

The output I would expect would be the output I get when I run python fire_bug.py. I am aware that if I have an __init__ method with arguments that the information about those arguments will be displayed, but separating the two sets of information in this way is quite counterintuitive. Both sets of information should be provided when running with no command and when running with only a --help argument.

dsirov commented 5 months ago

@JimBiardClimateAI Nice workaround with __str()__!

Workaround to make --help work too: instantiate the class yourself and pass the object to Fire:

Fire(Foo())

fire_bug --help now works (as well as chaining):

NAME
    fire_bug.py

SYNOPSIS
    fire_bug.py COMMAND

COMMANDS
    COMMAND is one of the following:

     act
       Act for some number of minutes.

     rest
       Rest for a while.