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?!"