google / python-fire

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

feature request: allow passing unparsed parameters #118

Open ophiry opened 6 years ago

ophiry commented 6 years ago

a common idiom in cli is to have a flag (usually --, but this is taken here) that all text afterwards is passed as is (mostly for passing to other commands)

it could be useful to have a similar feature in fire

for example:

example.py foo --- this is passed as is - --

example.py:

import fire

def hello(name, __unparsed__):
  print(name)
  print(__unparsed__)

if __name__ == '__main__':
  fire.Fire(hello)

will yield:

foo this is passed as is - --

dbieber commented 6 years ago

Thanks for the suggestion. What's your use case? For the example you gave above, you can achieve the desired behavior with quotes.

example.py foo "this is passed as is - --"

ophiry commented 6 years ago

The use case is wrapper scripts that do some kind of preprocessing, and then launch a second script with the rest of the params (similar to docker and ssh where the unparsed parameters are treated as a command to run) quoting will work, but gets ugly when the original parameters contain quotes

dbieber commented 6 years ago

I see. Yes, that's an important use case.

For now you should be able to do this with the experimental decorator @decorators.SetParseFn(str) and *varargs. However, this decorator is an undocumented / experimental feature, and the syntax for it may change in future versions of fire.

dbieber commented 6 years ago

For example, with the current implementation of these decorators you can do this:

import fire
import subprocess

@fire.decorators.SetParseFn(str)
@fire.decorators.SetParseFns(number_of_repeats=int)
def repeat_command(number_of_repeats, *command):
  for _ in range(number_of_repeats):
    subprocess.call(command)

if __name__ == '__main__':
  fire.Fire(repeat_command)

This enables running a command multiple times like so:

example.py 4 echo hello world

mtikekar commented 5 years ago

Hi, how can I make this work when the wrapped command has named options? For example, using the code above, if I do: python example.py 4 git --version, I get:

Fire trace:
1. Initial component
2. Called routine "repeat_command" (example.py:4)
3. ('Could not consume arg:', '--version')

I would like the command variable to get the tuple ('git', '--version')

link89 commented 2 years ago

The decorator trick seem not work in this case. I think we still need to have fire to inject some context into the function being executed to enable such feature.