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

Tuple of strings parsed as string if one of the strings contains a hyphen

Open kjxlstad opened this issue 1 year ago • 3 comments

When parsing in a tuple of strings i can normally pass in comma-separated values with no issues, however if one of the values contains a hyphen the arguments gets parsed as a string instead of a tuple of strings.

Using your provided example.py script

import fire
fire.Fire(lambda obj: type(obj).__name__)

If i call it with multiple strings not containing hyphens i get the expected output

>>> python example.py '(foobar,baz)' 
tuple

however, if I call it with a string containing a hyphen (-), I get this unexpected output

>>> python example.py '(foo-bar,baz)'
str

Is this to be expected? I also see that this is an issue with other symbols aswell. Is there a way to work around this other than to pass in a repr-like string?

E.g, this works, but is not very human friendly:

>>> python example.py '("foo-bar","baz")'
tuple

Edit: This is also the case for lists, sets and dicts containing strings.

kjxlstad avatar Sep 25 '24 08:09 kjxlstad

Thanks for reporting; this is indeed a confusing experience.

As you've discovered, you can get the behavior you want with python example.py '("foo-bar","baz")', but as you note, it is not human friendly.

Part of the reason for this is that the outermost quotes in whatever command you run are processed by your shell. This means that the seemingly logical python example.py ("foo-bar","baz") won't work either.

Is there a way to work around this other than to pass in a repr-like string? You could use the SetParseFn decorator to set your own arg parsing logic.

Now that we've dropped Python 2 support, we have the option of adding a feature for supporting type annotations to specify the parse function. Currently inputs are parsed based solely on their content, not based on the function expecting them. So this could improve the situation for functions annotated with arg: tuple[str]. We don't have active plans to add this feature either however.


My recommendation: If you're creating a CLI for other people to use, I recommend using @SetParseFn if you're accepting a sequence of strings. The current behavior of Fire is useful for if you're making a CLI (e.g. just for yourself) out of code you don't control, as it allows you to pass a sequence of strings if that's what's required, albeit sometimes requiring an uncomfortable syntax to do so.

dbieber avatar Sep 27 '24 18:09 dbieber

The same happens on dict type. And what makes things worse is, on Windows, you have to use double quote in the outside and single quote inside:

"{'local':'en-US'}" # type: dict
'{"local":"en-US"}' # type str

link89 avatar Nov 12 '24 10:11 link89

The official example produces different results when executed on Windows and Linux Execute under Linux: $ python example.py '{"name": "David Bieber"}' dict $ python example.py {"name":'"David Bieber"'}
dict $ python example.py {"name":"David Bieber"}
str $ python example.py {"name": "David Bieber"}
error $ python example.py '{"name": "Justin Bieber"}' dict

Execute under Windows: $ python example.py '{"name": "David Bieber"}'
error $ python example.py {"name":'"David Bieber"'} dict $ python example.py {"name":"David Bieber"}
str $ python example.py {"name": "David Bieber"}
error $ python example.py '{"name": "Justin Bieber"}' error

Do you suggest displaying these differences in Windows in the official documentation, or fixing the following to make Linux and Windows behave consistently?

wssf812 avatar Jun 13 '25 07:06 wssf812