google / python-fire

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

Unexpected printing (+paging) when using inspect #480

Closed drscotthawley closed 8 months ago

drscotthawley commented 8 months ago

Hi, when I use fire.Fire(), I find that it's printing variable info every time I use inspect, including pausing at every page boundary. I'd like to disable this unexpected printing behavior. Simple example code:

$ cat test.py
import inspect
import fire

def get_local_vars():
    """Return a dictionary of local variables."""
    return inspect.currentframe().f_back.f_locals

def vars_to_dict(variables):
    """Return a dictionary of variables."""
    return {var_name: var_value for var_name, var_value in variables.items()}

def my_routine(arg1, arg2):
    a = 10
    b = "Hello"
    c = [3, 4, 5]

    # Exclude function arguments (e.g. arg1, arg2) and only include truly local variables
    local_vars_dict = vars_to_dict({k: v for k, v in get_local_vars().items() if k not in get_local_vars()})
    return local_vars_dict

if __name__ == '__main__':
    #vals = my_routine("dummy_arg1", "dummy_arg2") # this works fine
    vals = fire.Fire(my_routine) # this produces unwanted print statements
    print("vals = ",vals)

Expected output from running python test.py dummy_arg1 dummy_arg2 is this:

vals =  {'arg1': 'dummy_arg1', 'arg2': 'dummy_arg2', 'a': 10, 'b': 'Hello', 'c': [3, 4, 5]}

but instead I see this:

arg1: dummy_arg1
arg2: dummy_arg2
a:    10
b:    Hello
c:    [3, 4, 5]
vals =  {'arg1': 'dummy_arg1', 'arg2': 'dummy_arg2', 'a': 10, 'b': 'Hello', 'c': [3, 4, 5]}

Those printed lines that start with arg1: dummy_arg1 through c: [3,4,5] are not in my code. Somehow Fire() is triggering print statements, unbidden. If there are many local variables, it even blocks execution at every printed-page boundary until the user manually presses Enter.

I don't have --verbose or --trace enabled. (Meaning verbose should be False unless it's set, right? or perhaps I need to say --verbose False?)

How do we disable this unbidden printing(+paging) behavior? Didn't see this mentioned in the Fire Guide.

Info:

$ pip list | grep fire
fire                      0.5.0

$ python --version
Python 3.11.6

Thanks!

drscotthawley commented 8 months ago

Seems the behavior is not unique to inspect. It seems that Fire will unexpectedly print even if you just access locals(). This is a side effect I'd love to disable.

Minimal example:

import fire

def my_routine(arg1, arg2):
    return locals()

if __name__ == '__main__':
    vals = fire.Fire(my_routine) # this produces unwanted print statements
    print("vals = ",vals)

Output includes not just the "vals = " line but two additional variable outputs that occur when locals() gets called while using Fire():

arg1: dummy_arg1
arg2: dummy_arg2
vals =  {'arg1': 'dummy_arg1', 'arg2': 'dummy_arg2'}

It's no so much the printing that's the problem per se, it's the fact that it blocks execution and waits for the user to press enter (if it prints more than a page of variables) that's the main problem.

dbieber commented 8 months ago

Fire displays the returned object on completion by default. To disable this, you can use:

noprint = lambda _: None
fire.Fire(my_routine, serialize=noprint)
drscotthawley commented 8 months ago

Awesome! Thank you very much! Closing.