[PYTHON] A little addictive information about Cliff, the CLI framework

Introduction

One of Python's CLI frameworks is Cliff. I would like to tell you something that I was a little addicted to.

About Cliff

See here for more information. It is a framework that makes it easy to create CLI tools. Just write a little bit and it will do a good job of returning program values and --help. Just create main.py and map it to the class of each command with setup.py etc.

About Cliff command classes

The most basic command class is the Command class. It's like making a command by inheriting this.

sample.py


from cliff.command import Command

class SampleCommand(Command):
    #~~What you want the command to do~~

Even by default, there are some classes that inherit from the Command class. If you want to return only one object, you can use ShowOne. , It will be made into a table without permission, or it will be made into JSON or YAML by specifying options.

Basically, the command is implemented as follows.

sample.py


from cliff.command import Command

class SampleCommand(Command):

    def get_parser(self, prog_name)
        parser = super().get_parser(prog_name)
        #Add argument
        parser.add_argument('something')    #Required arguments
        parser.add_argument('--some')       #Optional arguments
        parser.add_argument('--so', '-s')   #You can also add a shortened system
        return parser

    def take_action(self, parsed_args):
        #Execute processing
        return something

The return value in the above take_action will basically be returned at runtime. (Strictly speaking, take_action is wrapped in the run function, so if you do various things, it will be a mess.)

What I was addicted to

It is a story that when I tried to return JSON or dict in take_action of the command class that inherited the above Command class, the output of the command was only the standard error output.

sample.py


import json
from cliff.command import Command

class SampleCommand(Command):

    def get_parser(self, prog_name)
        parser = super().get_parser(prog_name)
        parser.add_argument('arg1')
        return parser

    def take_action(self, parsed_args):
        #Execute processing
        return json.dumps(something)

shell.sh


samplecommand arg1 > log
#For some reason the output comes out in the terminal!
samplecommand arg1 2> log
#There will be no output

The reason is that the return value of take_action in a command class that inherits from the Command class is the exit status of the command. In other words

sample.py


from cliff.command import Command

class SampleCommand(Command):

    def get_parser(self, prog_name)
        parser = super().get_parser(prog_name)
        parser.add_argument('arg1')
        return parser

    def take_action(self, parsed_args):
        #Execute processing
        return 100

When it becomes

shell.sh


samplecommand arg1
echo $?
#100 outputs

It will be. Since JSON, dict and other objects are basically judged as True, the return value of all commands will be 1, and if the exit status is 1, it will be an error judgment and will be output to the standard error output.

why.

(If you are fine, throw a pull request)

Recommended Posts

A little addictive information about Cliff, the CLI framework
A little more about FIFO
A little deeper story about blockchain, ticking the digital world
After researching the Python library, I understood a little about egg.info.
Miscellaneous notes about the Django REST framework
A note about doing the Pyramid tutorial
Get the latest AMI information with the AWS CLI
A Java programmer studied Python. (About the decorator)
I thought a little about TensorFlow's growing API
A note about the python version of python virtualenv
Django REST framework A little useful to know.
A memorandum about the Python tesseract wrapper library
A note about the new style base class
I did a little research on the class