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

Using `--help` with `file.Fire()` usage incorrectly prints imports and variables

Open aaronsteers opened this issue 5 years ago • 2 comments

When running --help against a program like the following, I expect a single my_func command but instead I get my_func, fire, logging, GREETING_MSG, and logger. I would like to be able to ignore python module imports and local variables by default.

import fire
import logging

GREETING_MSG = "Hello"

logger = logging.get_logger()

def _my_internal_hidden_func():
    # This is correctly ignored
    pass

def my_func():
    logger.info(f"{GREETING_MSG}, world")

if __name__ = "__main__":
    fire.Fire()

For the simple example above, the obvious resolution is to use a different method of invoking Fire() but for my actual use case, there are over 40 functions in the file I want to expose. For internal functions, I can hide these simply be preceeding the name with underscore, but I don't see any similar way of suppressing the imports and variable definitions.

I'd propose resolving this in one of two ways: (1) Add some kind of heuristic to the default fire.Fire() invocation to ignore imports and variables (2) Add some type of flags and/or lambda function support so the code consuming Fire can customize this logic without having to create and directly pass a custom dictionary of all functions.

Is anything like this already in progress, and/or would something along these lines be accepted as a pull request?

Thanks!

aaronsteers avatar Feb 18 '20 05:02 aaronsteers

BTW, this issue seems to be a more or less the same as #204, though this issue seems more verbose perhaps?

masq avatar Jun 25 '20 23:06 masq

I don't know what the status of the current issue is, however I just encountered this "bug" myself. I implemented this simple solution myself, which should be pretty straight forward to include if anybody so desires:

def _gen_fire_args() -> dict[str, Callable]:
    """Generate a dict of arguments to be called by fire.Fire()"""
    globals_ = globals()
    all_modules = set(sys.modules)
    imported_modules = all_modules & set(globals_)
    other_constants = set(globals_) - imported_modules

    return {
        name: callable
        for name in other_constants
        if not name.startswith("_")  # Exclude private constants
        and isinstance((callable := globals_[name]), Callable)  # Exclude non-callables
        and callable.__module__ == "__main__"  # Exclude imported callables
    }


if __name__ == "__main__":
    _fire_args = _gen_fire_args()

    fire.Fire(_fire_args)

gaardhus avatar Oct 23 '23 19:10 gaardhus