12

I have function like this -

def my_func(my_list_arg=["one", "two"]):

Which I'm trying to call from command line using python-fire.

I have tried several ways -


Attempt 1:

fire_runner.py my_func [one, two]

Results in two separate arguments "[one" and "two]".


Attempt 2:

fire_runner.py my_func ["one", "two"]

which has the same result.


Attempt 3:

fire_runner.py my_func [\"one\", \"two\"]

same result.

Duke79
  • 827
  • 1
  • 10
  • 21

6 Answers6

17

Your list will first be parsed by the command line shell. This means you need to force it as a single argument. There are many ways to do this:

  1. No space: [one,two]

  2. Escape the space: [one,\ two]

  3. Quotes: "[one, two]".

Note that you could modify your function to take a list of arguments using the following syntax:

def my_func(*args):

The name args here is convention, but it is just a variable name, so it can be anything. This will allow you to call your function as

fire_runner.py my_func one two
James Owers
  • 7,948
  • 10
  • 55
  • 71
Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • Strangely, none of the 3 methods at the top seem to work for me if the argument contains a full stop. It treats the list argument like a single string again. To reproduce: `fire_runner.py my_func [one,two.two]` (or anly of the other options) – James Owers Mar 04 '20 at 22:44
  • @JamesOwers The brackets or dot might have special meaning to the shell. I suggest reading about how to escape special characters for the specific shell you are using. – Code-Apprentice Mar 05 '20 at 16:59
  • 2
    Good point - i'm just using `bash`. However, given the error you'll get is: `KeyError: '[one,two.two]'`, we can deduce that the full stop is getting into the command ok. A clunky solution is to quote both the keys and the list: `fire_runner.py my_func "['one','two.two']"` – James Owers Mar 05 '20 at 19:51
5

Adding this answer just for a special case.

given that your function is like this:

def my_func(dates: List[str] = []):
    ...

In case you need to send list of dates (or any combination of numbers and characters) from the CLI, the following WON'T work.

fire_runner.py my_func --dates 2021-09-20,
fire_runner.py my_func --dates "[2021-09-20]"
fire_runner.py my_func --dates [2021-09-20]

In all the above cases, dates will be read as one string instead of list of strings. For proper reading of list of strings you can use the following.

fire_runner.py my_func --dates "[\"2021-09-20\"]"
fire_runner.py my_func --dates "[\"2021-09-20\", \"2021-09-76\"]"
roronoa
  • 407
  • 9
  • 14
  • Please note that having an empty list (ie a mutable element) as default argument of your function is a common bad practice in python and will do you no good – Théo Rubenach Jun 27 '22 at 17:02
  • 1
    @ThéoRubenach I believe it's only bad practice if you accidentally modify the mutable argument. If you are careful not to do this then I find that using `[]` is more intuitive to the use of your function than `None`. Plus it makes type hinting simpler. – Nick Crews Dec 15 '22 at 02:57
3

Not keeping any space after the comma worked for me.

fire_runner.py my_func [one,two]
Duke79
  • 827
  • 1
  • 10
  • 21
3

Fire converts a comma-separated digit string to tuple as follows:

fire_runner.py my_func  1,2,3

and for a comma-separated string you can use:

fire_runner.py my_func  \'2021-2\',\'20212-3\',\'2023-4\'
SlashGordon
  • 720
  • 8
  • 11
2

Adding a special corner case solution for one element lists, as the above syntaxes did not seem to work (list was parsed as a string starting with [ ):

fire_runner.py my_func "['one']"

Théo Rubenach
  • 484
  • 1
  • 4
  • 12
0

If you want to pass a list as argument, just separate the list item with comma (no space)
For example, for a file named fire_runner.py

# fire_runner.py
import fire
import json
def my_func(my_list_arg=["one", "two"]):
    print(json.dumps(locals(),indent=2))
    return

fire.Fire()

You can pass [one,two,three,four] to the function by typing

python fire_runner.py my_func one,two,three,four

results

{
  "my_list_arg": [
    "one",
    "two",
    "three",
    "four"
  ]
}

If you want pass one element list, ex. [one], just add a comma after the argument like this

python fire_runner.py my_func one,

results

{
  "my_list_arg": [
    "one"
  ]
}
hahaweweTMH
  • 26
  • 1
  • 3