0 前言

在Python开发和测试过程中主要有两种模式可以选择:脚本模式、命令行模式。在代码的开发和调试过程中使用脚本模式还是很方便的,尤其接触pycharm、eclipse这类强大的IDE,或者配合vs code这种综合的文本编辑器。但是如果使用纯文本编辑器,或者是在做整个系统开发时,与其他模型进行接口调用时,命令行模式就显得非常重要了。目前有很多热门的命令行工具,本文会一一介绍一下,并且重点介绍一下最近发现的一款命令行神器Click。
这款包配合setuptools的end_points参数可以,在命令行直接执行自定义的命令,而不需要使用python 脚本.py 参数这样的格式。

1 Click简介

Click 是 Flask 的团队 pallets 开发的优秀开源项目,它为命令行工具的开发封装了大量方法,使开发者只需要专注于功能实现。恰好我最近在开发的一个小工具需要在命令行环境下操作,就写个学习笔记。

2 Hello World

国际惯例,先来一段 “Hello World” 程序(假定已经安装了 Click 包)。

hello.py

import click@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name',help='The person to greet.')
def hello(count, name):"""Simple program that greets NAME for a total of COUNT times."""for x in range(count):click.echo('Hello %s!' % name)if __name__ == '__main__':hello()

执行结果为:

除此之外,Click 还悄悄地做了其他的工作,比如添加帮助选项:

$ python hello.py --help
Usage: hello.py [OPTIONS]Simple program that greets NAME for a total of COUNT times.Options:--count INTEGER  Number of greetings.--name TEXT      The person to greet.--help           Show this message and exit.

3 函数变CLI

3.1 command

从上面的 “Hello World” 演示中可以看出,Click 是通过装饰器来把一个函数方法装饰成命令行接口的,这个装饰器方法就是 @click.command()。

import click@click.command()
def hello():click.echo('Hello World!')

@click.command() 装饰器把 hello() 方法变成了 Command 对象,当它被调用时,就会执行该实例内的行为。而 --help 参数就是 Command 对象内置的参数。

3.2 group

不同的 Command 实例可以关联到 group 中。group 下绑定的命令就成为了它的子命令,参考下面的代码:

@click.group()
def cli():pass@click.command()
def initdb():click.echo('Initialized the database')@click.command()
def dropdb():click.echo('Dropped the database')cli.add_command(initdb)
cli.add_command(dropdb)
cli()

执行结果为:

@click.group 装饰器把方法装饰为可以拥有多个子命令的 Group 对象。由 Group.add_command() 方法把 Command 对象关联到 Group 对象。 也可以直接用 @Group.command 装饰方法,会自动把方法关联到该 Group 对象下。

@click.group()
def cli():pass@cli.command()
def initdb():click.echo('Initialized the database')@cli.command()
def dropdb():click.echo('Dropped the database')
cli()

执行结果为:

4 命令行参数介绍

命令行的参数功能是不可或缺的,Click 支持对 command 方法添加自定义的参数,由 option() 和 argument() 装饰器实现。

@click.command()
@click.option('--count', default=1, help='number of greetings')
@click.argument('name')
def hello(count, name):for x in range(count):click.echo('Hello %s!' % name)

上面使用了自定义命令行参数的两个装饰器:@click.option() 和 @click.argument(),两者有些许区别,使用场景也有所不同。
总体而言,argument() 装饰器比 option() 功能简单些。
option支持下面的特性:

  • 自动提示缺失的输入;
  • option 参数可以从环境变量中获取,argument 参数则不行;
  • option 参数在 help 输出中有完整的文档,argument 则没有;

而 argument 参数可以接受可变个数的参数值,而 option 参数只能接收固定个数的参数值(默认是 1 个)。
Click 可以设置不同的参数类型,简单类型如 click.STRING,click.INT,click.FLOAT,click.BOOL。
命令行的参数名由 “-short_name” 和 “–long_name” 声明,如果参数名既没有以 “-” 开头,也没有以 “–” 开头,那么这边变量名会成为被装饰方法的内部变量,而非方法参数。

4.1 option参数

option 最基础的用法就是简单值变量,option 接收一个变量值,下面是一段示例代码:

@click.command()
@click.option('--n', default=1)
def dots(n):click.echo('.' * n)

如果在命令行后面跟随参数 --n=2 就会输出两个点,如果传参数,默认输出一个点。上面的代码中,参数类型没有显示给出,但解释器会认为是 INT 型,因为默认值 1 是 int 值。 有些时候需要传入多个值,可以理解为一个 list,option 只支持固定长度的参数值,即设置后必须传入,个数由 nargs 确定。

@click.command()
@click.option('--pos', nargs=2, type=float)
def findme(pos):click.echo('%s / %s' % pos)

findme --pos 2.0 3.0 输出结果就是 2.0 / 3.0
既然可以传入 list,那么 tuple 呢?Click 也是支持的:

@click.command()
@click.option('--item', type=(unicode, int))
def putitem(item):click.echo('name=%s id=%d' % item)

这样就传入了一个 tuple 变量,putitem --item peter 1338 得到的输出就是 name=peter id=1338 上面没有设置 nargs,因为 nargs 会自动取 tuple 的长度值。因此上面的代码实际上等同于:

@click.command()
@click.option('--item', nargs=2, type=click.Tuple([unicode, int]))
def putitem(item):click.echo('name=%s id=%d' % item)

option 还支持同一个参数多次使用,类似 git commit -m aa -m bb 中 -m 参数就传入了 2 次。option 通过 multiple 标识位来支持这一特性:

@click.command()
@click.option('--message', '-m', multiple=True)
def commit(message):click.echo('\n'.join(message))

有时候,命令行参数是固定的几个值,这时就可以用到 Click.choice 类型来限定传参的潜在值:

# choice
@click.command()
@click.option('--hash-type', type=click.Choice(['md5', 'sha1']))
def digest(hash_type):click.echo(hash_type)

当上面的命令行程序参数 --hash-type 不是 md5 或 sha1,就会输出错误提示,并且在 --help 提示中也会对 choice 选项有显示。
既然支持 Choice,不难联想到 Range,先看代码:

# range
@click.command()
@click.option('--count', type=click.IntRange(0, 20, clamp=True))
@click.option('--digit', type=click.IntRange(0, 10))
def repeat(count, digit):click.echo(str(digit) * count)if __name__ == '__main__':repeat()

如果希望命令行程序能在我们错误输入或漏掉输入的情况下,友好的提示用户,就需要用到 Click 的 prompt 功能,看代码:

# prompt
@click.command()
@click.option('--name', prompt=True)
def hello(name):click.echo('Hello %s!' % name)

如果在执行 hello 时没有提供 –name 参数,控制台会提示用户输入该参数。也可以自定义控制台的提示输出,把 prompt 改为自定义内容即可。如第一部分的hello world中的prompt设置为Your name。
对于类似账户密码等参数的输入,就要进行隐藏显示。option 的 hide_input 和 confirmation_promt 标识就是用来控制密码参数的输入:

# password
@click.command()
@click.option('--password', prompt=True, hide_input=True,confirmation_prompt=True)
def encrypt(password):click.echo('Encrypting password to %s' % password.encode('rot13'))

Click 把上面的操作进一步封装成装饰器 click.password_option(),因此上面的代码也可以简化成:

# password
@click.command()
@click.password_option()
def encrypt(password):click.echo('Encrypting password to %s' % password.encode('rot13'))

有的参数会改变命令行程序的执行,比如 node 是进入 Node 控制台,而 node --verion 是输出 node 的版本号。Click 提供 eager 标识对参数名进行标记,拦截既定的命令行执行流程,而是调用一个回调方法,执行后直接退出。下面模拟 click.version_option() 的功能,实现 --version 参数名输出版本号:

# eager
def print_version(ctx, param, value):if not value or ctx.resilient_parsing:returnclick.echo('Version 1.0')ctx.exit()@click.command()
@click.option('--version', is_flag=True, callback=print_version,expose_value=False, is_eager=True)
def hello():click.echo('Hello World!')if __name__ == '__main__':hello()

运行结果:

对于类似删除数据库表这样的危险操作,Click 支持弹出确认提示,–yes 标识位置为 True 时会让用户再次确认:

# yes parameters
def abort_if_false(ctx, param, value):if not value:ctx.abort()@click.command()
@click.option('--yes', is_flag=True, callback=abort_if_false,expose_value=False,prompt='Are you sure you want to drop the db?')
def dropdb():click.echo('Dropped all tables!')

测试运行下:

$ dropdb
Are you sure you want to drop the db? [y/N]: n
Aborted!
$ dropdb --yes
Dropped all tables!

同样的,Click 对次进行了封装,click.confirmation_option() 装饰器实现了上述功能:

@click.command()
@click.confirmation_option(prompt='Are you sure you want to drop the db?')
def dropdb():click.echo('Dropped all tables!')

前面只讲了默认的参数前缀 – 和 -,Click 允许开发者自定义参数前缀(虽然严重不推荐)。

# other prefix
@click.command()
@click.option('+w/-w')
def chmod(w):click.echo('writable=%s' % w)if __name__ == '__main__':chmod()

如果想要用 / 作为前缀,而且要像上面一样采用布尔标识,会产生冲突,因为布尔标识也是用 /,这种情况下可以用 ; 代替布尔标识的 /:

@click.command()
@click.option('/debug;/no-debug')
def log(debug):click.echo('debug=%s' % debug)if __name__ == '__main__':log()

4.2 argument 参数

Argument 的作用类似 Option,但没有 Option 那么全面的功能。

和 Option 一样,Argument 最基础的应用就是传递一个简单变量值:

@click.command()
@click.argument('filename')
def touch(filename):click.echo(filename)

命令行后跟的参数值被赋值给参数名 filename。

另一个用的比较广泛的是可变参数,也是由 nargs 来确定参数个数,变量值会以 tuple 的形式传入函数:

@click.command()
@click.argument('src', nargs=-1) #-1表示可以接受不确定数量的参数
@click.argument('dst', nargs=1)
def copy(src, dst):for fn in src:click.echo('move %s to folder %s' % (fn, dst))

运行程序:

$ copy foo.txt bar.txt my_folder
move foo.txt to folder my_folder
move bar.txt to folder my_folder

Click 支持通过文件名参数对文件进行操作,click.File() 装饰器就是处理这种操作的,尤其是在类 Unix 系统下,它支持以 - 符号作为标准输入/输出。

# File
import click
@click.command()
@click.argument('input', type=click.File('rb'))
@click.argument('output', type=click.File('wb'))
def inout(input, output):chunk = input.readline()output.write(chunk)if __name__ == '__main__':inout()

运行程序,将文本写进文件


经过试验option好像不支持这种文件对象参数。

如果参数值只是想做为文件名而已呢,很简单,将 type 指定为 click.Path():

@click.command()
@click.argument('f', type=click.Path(exists=True))
def touch(f):click.echo(click.format_filename(f))

5 打包跨平台可执行程序

通过 Click 编写了简单的命令行方法后,还需要把 .py 文件转换成可以在控制台里运行的命令行程序。最简单的办法就是在文件末尾加上如下代码:

if __name__ == '__main__':command_name()

Click 支持使用 setuptools 来更好的实现命令行程序打包,把源码文件打包成系统中的可执行程序,并且不限平台。一般我们会在源码根目录下创建 setup.py 脚本,先看一段简单的打包代码:
setup.py

from setuptools import setupsetup(name='hello',version='0.1',py_modules=['hello'],install_requires=['Click',],entry_points='''[console_scripts]hello=hello:cli''',
)

留意 entry_points 字段,在 console_scripts 下,每一行都是一个控制台脚本,等号左边的的是脚本的名称,右边的是 Click 命令的导入路径。
我们使用上面的打包程序,对下面的代码进行打包:

# hello.py
import click@click.group()
def cli():pass@cli.command()
def initdb():click.echo('Initialized the database')@cli.command()
def dropdb():click.echo('Dropped the database')
cli()

打包命令:

然后进行安装和运行:

有关python打包和运行的详细内容看考博客:python程序的打包和安装

原文链接:Python Click 学习笔记

python命令行操作:Click包相关推荐

  1. python 命令行 模块_深入浅析Python 命令行模块 Click

    Click 是用 Python 写的一个第三方模块,用于快速创建命令行.我们知道,Python 内置了一个 Argparse 的标准库用于创建命令行,但使用起来有些繁琐,Click 相比于 Argpa ...

  2. Python命令行神器 Click 入门笔记

    高级教学参考: https://zhuanlan.zhihu.com/p/93738095 Click Click(https://github.com/pallets/click) 是用 Pytho ...

  3. TCPDUMP(命令行操作)-抓包、筛选、高级筛选、过程文档记录

    TCPDUMP No-GUI的抓包分析工具 Linux.Unix系统默认安装 TCPdump-–抓包 抓包 默认只抓68个字节 tcpdump -i eth0 -s 0 -w file.pcap tc ...

  4. python 基础命令-Python 命令行(CLI)基础库

    在 CLI 下写 UI 应用 前阵子看了一下自己去年写的 Python-视频转字符动画,感觉好糗..所以几乎把整篇文章重写了一遍.并使用 curses 库实现字符动画的播放. 但是感觉,curses ...

  5. Python 命令行参数:Argparse 与 Click

    Python 命令行参数:Argparse 与 Click 简介 一.Argparse 模块 1.1 概念 1.2 基础 1.3 位置参数介绍 1.4 可选参数介绍 1.5 短选项 1.6 结合位置参 ...

  6. Python命令行参数解析模块------argparse

      首先,argparse 是python自带的命令行参数解析包,可以用来方便地读取命令行参数,当你的代码需要频繁地修改参数的时候,使用这个工具可以将参数和代码分离开来,让你的代码更简洁,适用范围更广 ...

  7. linux基础命令行操作【1】

    目录 1.基本命令 2.文件相关知识 3.文本相关操作 4.文件解压.压缩.打包命令 1.基本命令 Ctrl+A/t+Fn+F6:管理Linux(Fn+数字) Linux:输入密码是不显示 Alt+F ...

  8. Python命令行可视化库

    我们通常都是在自己的电脑上跑程序,直接是可以可视化相应的结果.如果是在服务器上的话,使用终端,是不太方便查看结果.本文介绍4个可以在命令行中使用的Python库,分别是 Bashplotlib tqd ...

  9. 如何使用命令行清除NuGet包缓存?

    本文翻译自:How to clear NuGet package cache using command line? I can clear my dev computer's NuGet packa ...

最新文章

  1. html.partial mvc,MVC Html.Partial or Html.Action
  2. 如何找出应用程序未使用绑定变量
  3. 【Android 热修复】热修复原理 ( 类加载分析 | 分析 PathClassLoader 源码 | 分析 BaseDexClassLoader 源码 | 分析 PathDexList 源码 )
  4. 设计模式解析学习(一)
  5. 查询Linux系统最后重启时间的三个方法
  6. flex4 s:Datagrid s:typicalItem
  7. A small tip to explore how to call a method of a control
  8. SE37 test sequence - 在同一个main session内依次执行function module
  9. Mybatis-Plus的SQL语句组拼原理
  10. PAT乙级 1013 数素数
  11. python把图片存放到数据库_使用Python把图片存入数据库
  12. 第三方平台也能为未微信认证的订阅号调用自定义菜单接口和素材管理接口
  13. ALSA驱动中snd_soc_write()原理分析及demo(二十二)
  14. 机器学习的十大经典算法,面试必问
  15. 【b站黑马程序员C++视频学习笔记-文件操作】
  16. 计算机主机前声音口怎么设置吗,电脑前面的插孔没声音怎么设置
  17. BlackBerry 9850 应用:CISCO WebEx会议
  18. UE5导入MetaHuman虚拟头像后,连接live link face,面部表情捕捉出错修正
  19. macOS safari安装第三方插件
  20. Ubuntu 设置桥接网络

热门文章

  1. 字节跳动Android开发大牛:90% 成功率的 BATZ Offer 收割机是怎样练成的!
  2. Linux系统中VCS、Dve Verdi的使用
  3. spring boot 中阿里druid 数据源配置及密码加密
  4. canopen 报文格式_CANopen协议报文处理
  5. python语言所使用的特殊含义符号_Python3 正则表达式特殊符号及用法
  6. dxp全称_ad对应的器件名称
  7. oracle12c用plsql连不上,PLSQL连接oracle12c
  8. python爬取微博热搜显示到折线图_Python爬取新浪微博热搜榜-Go语言中文社区
  9. 数字人民币应用日渐成熟,领先美欧至少5年
  10. App手机应用自建平台 无需编码技术 轻松制作