Python Fire – Generates CLIs from any Python object

(github.com)

252 points | by tzury 2078 days ago

15 comments

  • dbieber 2077 days ago
    Author of Fire here. Was super happy to pass the 10000 star mark on GitHub today thanks to this HN post :) -- that boosted my spirits on an otherwise long and rainy (and now delayed) bus ride.

    Hope you find Fire useful!

    What's next for Python Fire? We're working on improving the help screens and usage outputs so it feels less like a developer tool and more like a professional grade CLI. So stay tuned as it gets better!

    • np_tedious 2077 days ago
      Great library. Excited to see that in 0.1.2 you removed nearly every dependency except `six` (esp ipython).

      This caused me to have to remove `fire` from a project repo's requirements.txt so that ipython wouldn't be included in production builds. Then in the testing script that used it, there was a comment saying "you're going to need ipython for this"

    • tzury 2077 days ago
      thanks for writing this!
  • devxpy 2077 days ago
    I have tried this before, and all I can say is that you should probably just use click over anything else.

    http://click.pocoo.org/5/

    • noobermin 2077 days ago
      Allow me to fan the flames. I find for simple scripts, docopt[0] is more than enough. It looks like the click's docs has a discussion of the differences.

      [0] http://docopt.org/

    • ramses0 2077 days ago
      Click makes python attractive for CLI's. It is far better than bash and perl for simple stuff. Fire looks useful for hacks but Click has been excellently intuitive for me.
      • slobotron 2077 days ago
        Perl6 has nice builtin cli construction from method definitions and doc comments

            cat > cli.pl6
        
            #| Duplicates without frobnication
            multi sub MAIN( 'duplicate', Int $times, Str $text ) {
              say $text x $times;
            }
            
            #| Frobnicates up to a limit
            multi sub MAIN('frobnicate', Int :$length = 24, Bool :v(:$verbose))
            {
                say 'Verbosity ', ($verbose ?? 'on' !! 'off');
            }
        
        
            perl6 cli.pl
            Usage:
              cli.pl6 duplicate <times> <text> -- Duplicates without frobnication
              cli.pl6 [--length=<Int>] [-v|--verbose] frobnicate -- Frobnicates up to a limit
        
        
            perl6 cli.pl6 duplicate 3 blah...
            blah...blah...blah...
      • vultour 2077 days ago
        The builtin argparse module is also really easy to use for simple stuff.
        • m_ke 2077 days ago
          It's ok but for some scripts it ends up being half of the code and you end up with a script that's dealing with an opaque args object.

          Here's a decent example of this https://github.com/pytorch/examples/blob/master/imagenet/mai...

          • heavenlyblue 2077 days ago
            Could you solve ghat with click much easier? This seems mostly related to various flags set up, which would need to exist in the code anyway.
            • m_ke 2077 days ago
              I'm saying that this should really be a function like

                  def train(
                    data: File,
                    arch='resnet18',
                    workers=4,
                    epochs=90,
                    start_epoch=0,
                    batch_size=256,
                    learning_rate=0.9,
                    momentum=1e-4,
                ):
                  ...
              
              
              that could be exposed as a cli if __name__ is main but otherwise can be imported in a notebook or another script.
    • bede 2077 days ago
      Fire is an interesting project that's great for testing and hacking. But for crafting Python CLIs from scratch, I fail to understand why Argh[0] doesn't receive more attention.

      My only frustrations are a missing default handler for --version, and that I can't use argument names colliding with builtins such as 'input'. All the flexibility of argparse without boilerplate.

      [0] https://github.com/neithere/argh

  • shezi 2077 days ago
    I am the author of commandeer[1], which does similar things and has been around since 2013. Try that, too, if you're interested!

    Seeing another library that makes it easier to access things from the command line is awesome, and finding that there are even more I didn't know about in the comments is even better.

    [1] https://commandeer.readthedocs.io/en/latest/

  • m_ke 2077 days ago
    I was looking for something similar to click / fire that uses type annotations to validate/cast the inputs today. Came across this https://github.com/Lucretiel/autocommand

    I think it would be really nice to have a library that takes the type annotated functions and lets you expose them as a CLI, GUI, REST API and a web form. Practically just combining click, flask, rest framework and Gooey. Would be a great tool for data scientists.

    Take something like

        def recognize(image: Image) -> List[Prediction]
          preds = model(image)
          return preds
    
    and generate web page that lets you drop an image in and get a list of predictions
  • crazysim 2077 days ago
    How about a mix with gooey?

    https://github.com/chriskiehl/Gooey

    That'll be neat.

    • goostavos 2077 days ago
      Hey, that's my lib! ^_^
      • mlevental 2077 days ago
        cool. two questions: is gooey cross-platform? and can I build an app starting with gooey rather "port" an existing cli app? what I mean is can I pick and widgets and stuff from the gooey widget library by hand rather than make it parse my Args thing object.
        • goostavos 2077 days ago
          Yep! It'll run on most flavors of Windows, Linux, and OSX.

          On the latter part, nah, not really. Gooey builds all of its widgets internally. There has been some interest in Gooey exposing the little pre-baked components it uses as a util library, but I haven't explored the option super deeply

          • mlevental 2077 days ago
            so just to be clear: i have to build a cli first and then gooey can works its magic. no way to skip the cli?
  • rllin 2077 days ago
    we use this in production (flags for kube execs of python scripts)

    it is bounds better than argparse and click. would highly recommend.

    important to note here, that a lot of this is thanks to the python team's continued extension of the inspect module.

  • syntaxing 2077 days ago
    Wow this is interesting. I never knew a tool like this existed. Seeing all the alternatives in the comments here is great too. It's like getting a solution to a problem I never knew I had! Super excited to use this on my next project!
  • samuell 2077 days ago
    Nice! This is an approach I hope will be used much more, to generate CLIs and other interfaces.

    Luigi [1] does something similar, in that it auto-creates an API that lets you call any task in your task dependency graph, and provide parameters as arguments to flags. One of the things that made working with Luigi such a breeze (although we experienced other problems for our use cases).

    [1] https://github.com/spotify/luigi

  • kaushalmodi 2077 days ago
    I've been using a similar library in Nim called cligen[0]. Like Fire, it infers the CLI long form/short form switches from the arguments of the function it is linking to. Follow the repo link for examples.

    [0]: https://github.com/c-blake/cligen

  • ijidak 2077 days ago
    Anyone know of something like this for .NET objects?

    I've never thought of something like this, but this would be very useful for many platforms.

  • edhu2017 2077 days ago
    seems great for my reinforcement learning models. instead of parsing my hyperparameters through the tensorflow cli API and editing the training file a line at a time to take in an additional hyperparameter, I can just directly set them through the cli with fire.
    • blt 2077 days ago
      but then how will you keep track of which parameters worked well? I've been essentially storing my kwargs in json and not felt a need to control anything directly from the CLI.
      • edhu2017 2077 days ago
        Good question, for me I programatically generate a folder with the hyperparameter key - values in the name and store the checkpoints under it. As you can imagine, it can get out of control quickly if not managed well, but it works for 1-3 person projects. For anything more large scale or organized, I would recommend looking into Comet ML which lets you query and filter your experiments by hyperparameter ranges instead of manually looking at folder names.
        • blt 2076 days ago
          I did that until I hit the Linux directory name length limit, lol. Now I hash the hyperparameters dict to get the directory name, and store a json file within. Totally ad hoc and I'm sure a better solution exists.
  • agumonkey 2078 days ago
    I wanted to do such thing since forever. Kudos (and I'm frustrated :)
  • softinio 2077 days ago
    this isn't new but I am glad its reported as I had completely forgotten about it. Will give it a try on next CLI project for sure.
  • Walkman 2077 days ago
    I always wondered how far human laziness can go? This is an absolutely terrible library. Every command line is a HUMAN INTERFACE for interactions with your program, should not exposed random methods for command line usage...

    Also, developing a Python library and not keeping the most basic standard (PEP8)? You should not be allowed near Python. I really have no better words for this, just fucking lazy. I hate lazy developers, because you are the reason most software is shit.