Stay Hungry,Stay Foolish!

CLI makers

Argparse

https://www.geeksforgeeks.org/argparse-vs-docopt-vs-click-comparing-python-command-line-parsing-libraries/

python内置库。

使用代码形式定义CLI.

 

Argparse is a user-friendly command line interface. The argparse module parses the command-line arguments and options/flags.

 

# argparse_example.py

import argparse

if __name__=='__main__':
    
    #Initialize
    parser=argparse.ArgumentParser(description="Simple calculator")
    
    #Adding optional parameters
    parser.add_argument('-n1',
                        '--num1',
                        help="Number 1",
                        type=float)

    parser.add_argument('-n2',
                        '--num2',
                        help="Number 2",
                        type=float)

    parser.add_argument('-op',
                        '--operation',
                        help="operator",
                        default="*")
    
    #Parsing the argument
    args=parser.parse_args()
    print(args)

    #Initialize result to None
    result =None

    #Simple calculator operations
    if args.operation == '+':
        result=args.num1+args.num2

    if args.operation == '-':
        result=args.num1-args.num2

    if args.operation == '/':
        result=args.num1/args.num2

    if args.operation == '*':
        result=args.num1*args.num2

    if args.operation == 'pow':
        result=pow(args.num1,args.num2)
    
    #Print the result
    print("Result = " ,result)

 

CLICK

https://www.geeksforgeeks.org/argparse-vs-docopt-vs-click-comparing-python-command-line-parsing-libraries/

argparse升级版本,flask团队实现。

 

使用装饰器把参数绑定到main函数的参数上。

除了argparse外,被使用的最广泛的一个库,功能丰富。

https://click.palletsprojects.com/en/8.1.x/

 

Click is a Command Line Interface Creation Kit, it helps in arbitrary nesting of commands, automatic help page generation, supports lazy loading of subcommands at runtime. It aims to make the process of writing command-line tools quick and fun while also preventing any frustration caused by the inability to implement an intended CLI API. It comes with useful common helpers (getting terminal dimensions, ANSI colors, fetching direct keyboard input, screen clearing, finding config paths, launching apps and editors, etc.)

 

# click_example.py

import click

# initialize result to 0
result=0

@click.command()
@click.option('--num1',
            default=1,
            help='Enter a float value',
            type=float)

@click.option('--num2',
            default=1,
            help='Enter a float value',
            type=float)

@click.option('--op',
            default='+',
            help='Enter the operator')

# Calculator function
def calculator(num1,num2,op):
    if op=='+':
        result=num1+num2
    if op=='*':
        result=num1*num2
    if op=='-':
        result=num1-num2
    if op=='/':
        result=num1/num2

    # print the result
    click.echo("Result is %f" %result)

if __name__ =='__main__':
    calculator()

Typer

https://typer.tiangolo.com/

click的升级版本, 依赖click实现。

FASTAPI团队实现。

 

依赖注入方式,对每个参数做注解

相对click,更加implict。

 

Typer is a library for building CLI applications that users will love using and developers will love creating. Based on Python 3.6+ type hints.

The key features are:

  • Intuitive to write: Great editor support. Completion everywhere. Less time debugging. Designed to be easy to use and learn. Less time reading docs.
  • Easy to use: It's easy to use for the final users. Automatic help, and automatic completion for all shells.
  • Short: Minimize code duplication. Multiple features from each parameter declaration. Fewer bugs.
  • Start simple: The simplest example adds only 2 lines of code to your app: 1 import, 1 function call.
  • Grow large: Grow in complexity as much as you want, create arbitrarily complex trees of commands and groups of subcommands, with options and arguments.

 

import typer

app = typer.Typer()


@app.command()
def hello(name: str):
    print(f"Hello {name}")


@app.command()
def goodbye(name: str, formal: bool = False):
    if formal:
        print(f"Goodbye Ms. {name}. Have a good day.")
    else:
        print(f"Bye {name}!")


if __name__ == "__main__":
    app()

 

 

Docopt

https://www.geeksforgeeks.org/argparse-vs-docopt-vs-click-comparing-python-command-line-parsing-libraries/

使用文档的风格定义CLI

别具一格。

https://github.com/docopt/docopt

http://docopt.org/

 

Docopt creates command line interface for the command line app, it automatically generates a parser for it. The main idea of docopt is to describe the interface literally with text, as in docstring.

#docopt_example.py

#usage pattern
usage='''

Usage:
docopt_example.py command --option <argument>
docopt_example.py <argument> <repeating-argument>
docopt_example.py --version

Options:
-h, --help     Display help
-o, --option Display options
-l, --all     List all
-q, --quit     exit
--version     Version 3.6.1
    
'''

#Initialization
from docopt import docopt

args=docopt(usage)
print(args)

 

简单例

https://riptutorial.com/python/example/4501/basic-example-with-docopt

"""
Usage:
    script_name.py [-a] [-b] <path>

Options:
    -a            Print all the things.
    -b            Get more bees into the path.
"""
from docopt import docopt


if __name__ == "__main__":
    args = docopt(__doc__)
    import pprint; pprint.pprint(args)

解析结果存储在args中

$ python script_name.py
Usage:
    script_name.py [-a] [-b] <path>
$ python script_name.py something
{'-a': False,
 '-b': False,
 '<path>': 'something'}
$ python script_name.py something -a
{'-a': True,
 '-b': False,
 '<path>': 'something'}
$ python script_name.py -b something -a
{'-a': True,
 '-b': True,
 '<path>': 'something'}

子命令例

https://github.com/rgreinho/docopt-subcommands-example/blob/master/main.py

#! /usr/bin/env python
"""
Control center for an imaginary video game.
usage:
    control [-hv] [-n NAME] <command> [<args>...]
options:
    -h, --help                  shows the help
    -n NAME --name=NAME         sets player name [default: player]
    -v, --version               shows the version
The subcommands are:
    greet   greets other players
    jump    makes the player jump
    run     makes the player run
"""

from docopt import docopt
from docopt import DocoptExit

import commands

if __name__ == '__main__':
    args = docopt(__doc__, version='1.0.0', options_first=True)

    # Retrieve the command to execute.
    command_name = args.pop('<command>').capitalize()

    # Retrieve the command arguments.
    command_args = args.pop('<args>')
    if command_args is None:
        command_args = {}

    # After 'poping' '<command>' and '<args>', what is left in the args dictionary are the global arguments.

    # Retrieve the class from the 'commands' module.
    try:
        command_class = getattr(commands, command_name)
    except AttributeError:
        print('Unknown command. RTFM!.')
        raise DocoptExit()

    # Create an instance of the command.
    command = command_class(command_args, args)

    # Execute the command.
    command.execute()

 

https://github.com/rgreinho/docopt-subcommands-example/blob/master/commands.py

from docopt import docopt


class AbstractCommand:
    """Base class for the commands"""

    def __init__(self, command_args, global_args):
        """
        Initialize the commands.
        :param command_args: arguments of the command
        :param global_args: arguments of the program
        """
        self.args = docopt(self.__doc__, argv=command_args)
        self.global_args = global_args

    def execute(self):
        """Execute the commands"""
        raise NotImplementedError


class Run(AbstractCommand):
    """
    Defines how long a player will run.
    usage:
        run ( --distance=<meters> | --time=<seconds> )
    options:
        --distance=<meters>     Player runs for <meters> meters.
        --time=<seconds>        Player run for <seconds> seconds.
    """

    def execute(self):
        if self.args['--distance']:
            if int(self.args['--distance']) > 100:
                print('Are you crazy? {} is not going to do that!'.format(self.global_args['--name']))
                return
            print('{} is going to run {} meters.'.format(self.global_args['--name'], self.args['--distance']))
        elif self.args['--time']:
            if int(self.args['--time']) > 10:
                print('Are you crazy? {} not going to do that!'.format(self.global_args['--name']))
                return
            print('{} is going to run for {} seconds.'.format(self.global_args['--name'], self.args['--time']))


class Jump(AbstractCommand):
    """
    Defines how far a player will jump.
    usage:
        jump --distance=<meters>
    options:
        --distance=<meters>     Player jumps for <meters> meters.
    """

    def execute(self):
        print('{} is going to jump {} meters.'.format(self.global_args['--name'], self.args['--distance']))

class Greet(AbstractCommand):
    """
    Greets others players.
    usage:
        greet
    """

    def execute(self):
        print('Hi other player(s)!')

 

HUG

https://hugapi.github.io/hug/

亮点是, 一个库, 对CLI和API通吃。

hug aims to make developing Python driven APIs as simple as possible, but no simpler. As a result, it drastically simplifies Python API development.

hug's Design Objectives:

  • Make developing a Python driven API as succinct as a written definition.
  • The framework should encourage code that self-documents.
  • It should be fast. A developer should never feel the need to look somewhere else for performance reasons.
  • Writing tests for APIs written on-top of hug should be easy and intuitive.
  • Magic done once, in an API framework, is better than pushing the problem set to the user of the API framework.
  • Be the basis for next generation Python APIs, embracing the latest technology.

As a result of these goals, hug is Python 3+ only and built upon Falcon's high performance HTTP library

 

import hug


@hug.get()
def hello(request):
    """Says hellos"""
    return "Hello Worlds for Bacon?!"

 

posted @ 2022-10-29 18:50  lightsong  阅读(9)  评论(0编辑  收藏  举报
Life Is Short, We Need Ship To Travel