Python 命令行之旅:深入 click 之增強功能
掃描二維碼
隨時隨地手機看文章
一、前言
在前面三篇文章中,我們介紹了 click中的參數(shù)、選項和命令,本文將介紹
click錦上添花的功能,以幫助我們更加輕松地打造一個更加強大的命令行程序。
本系列文章默認使用 Python 3 作為解釋器進行講解。
若你仍在使用 Python 2,請注意兩者之間語法和庫的使用差異哦~
二、增強功能
2.1 Bash 補全
Bash 補全是 click提供的一個非常便捷和強大的功能,這是它比 argpase和 docopt強大的一個表現(xiàn)。
在命令行程序正確安裝后,Bash 補全才可以使用。而如何安裝可以參考 setup 集成。Click 目前僅支持 Bash 和 Zsh 的補全。
2.1.1 補全能力
通常來說,Bash 補全支持對子命令、選項、以及選項或參數(shù)值得補全。比如:
$ repoclone commit copy delete setuser
$ repo clone ---deep --help --rev --shallow -r
此外,click還支持自定義補全,這在動態(tài)生成補全場景中很有用,使用 autocompletion參數(shù)。autocompletion需要指定為一個回調(diào)函數(shù),并且返回字符串的列表。此函數(shù)接受三個參數(shù):
-
ctx—— 當前的 click 上下文
-
args傳入的參數(shù)列表
-
incomplete正在補全的詞
這里有一個根據(jù)環(huán)境變量動態(tài)生成補全的示例:
import os def get_env_vars(ctx, args, incomplete): return [k for k in os.environ.keys() if incomplete in k] @click.command() @click.argument("envvar", type=click.STRING, autocompletion=get_env_vars) def cmd1(envvar): click.echo('Environment variable: %s' % envvar)
click.echo('Value: %s' % os.environ[envvar])
在 ZSH中,還支持補全幫助信息。只需將 autocompletion回調(diào)函數(shù)中返回的字符串列表中的字符串改為二元元組,第一個元素是補全內(nèi)容,第二個元素是幫助信息。
這里有一個顏色補全的示例:
import os def get_colors(ctx, args, incomplete): colors = [('red', 'help string for the color red'),
('blue', 'help string for the color blue'),
('green', 'help string for the color green')] return [c for c in colors if incomplete in c[0]] @click.command() @click.argument("color", type=click.STRING, autocompletion=get_colors) def cmd1(color): click.echo('Chosen color is %s' % color)
2.1.2 激活補全
要激活 Bash 的補全功能,就需要告訴它你的命令行程序有補全的能力。通常通過一個神奇的環(huán)境變量 __COMPLETE來告知,其中 是大寫下劃線形式的程序名稱。
比如有一個命令行程序叫做 foo-bar,那么對應(yīng)的環(huán)境變量名稱為 _FOO_BAR_COMPLETE,然后在 .bashrc中使用 source導出即可:
eval "$(_FOO_BAR_COMPLETE=source foo-bar)"
或者在 .zshrc中使用:
eval "$(_FOO_BAR_COMPLETE=source_zsh foo-bar)"
不過上面的方式總是在命令行程序啟動時調(diào)用,這可能在有多個程序時減慢 shell 激活的速度。另一種方式是把命令放在文件中,就像這樣:
# 針對 Bash _FOO_BAR_COMPLETE=source foo-bar > foo-bar-complete.sh # 針對 ZSH _FOO_BAR_COMPLETE=source_zsh foo-bar > foo-bar-complete.sh
然后把腳本文件路徑加到 .bashrc或 .zshrc中:
. /path/to/foo-bar-complete.sh
2.2 實用工具
2.2.1 打印到標準輸出
echo() 函數(shù)可以說是最有用的實用工具了。它和 Python 的 print類似,主要的區(qū)別在于它同時在 Python 2 和 3 中生效,能夠智能地檢測未配置正確的輸出流,且?guī)缀醪粫。ǔ?Python 3 中的少數(shù)限制。)
echo即支持 unicode,也支持二級制數(shù)據(jù),如:
import click
click.echo('Hello World!')
click.echo(b'\xe2\x98\x83', nl=False) # nl=False 表示不輸出換行符
2.2.2 ANSI 顏色
有些時候你可能希望輸出是有顏色的,這尤其在輸出錯誤信息時有用,而 click在這方面支持的很好。
首先,你需要安裝 colorama:
pip install colorama
然后,就可以使用 style() 函數(shù)來指定顏色:
import click
click.echo(click.style('Hello World!', fg='green'))
click.echo(click.style('Some more text', bg='blue', fg='white'))
click.echo(click.style('ATTENTION', blink=True, bold=True))
click還提供了更加簡便的函數(shù) secho,它就是 echo和 style的組合:
click.secho('Hello World!', fg='green')
click.secho('Some more text', bg='blue', fg='white')
click.secho('ATTENTION', blink=True, bold=True)
2.2.3 分頁支持
有些時候,命令行程序會輸出長文本,但你希望能讓用戶盤也瀏覽。使用 echo_via_pager() 函數(shù)就可以輕松做到。
例如:
def less(): click.echo_via_pager('\n'.join('Line %d' % idx for idx in range(200)))
如果輸出的文本特別大,處于性能的考慮,希望翻頁時生成對應(yīng)內(nèi)容,那么就可以使用生成器:
def _generate_output(): for idx in range(50000): yield "Line %d\n" % idx @click.command() def less(): click.echo_via_pager(_generate_output())
2.2.4 清除屏幕
使用 clear() 可以輕松清除屏幕內(nèi)容:
import click
click.clear()
2.2.5 從終端獲取字符
通常情況下,使用內(nèi)建函數(shù) input或 raw_input獲得的輸入是用戶輸出一段字符然后回車得到的。但在有些場景下,你可能想在用戶輸入單個字符時就能獲取到并且做一定的處理,這個時候 getchar() 就派上了用場。
比如,根據(jù)輸入的 y或 n做特定處理:
import click
click.echo('Continue? [yn] ', nl=False)
c = click.getchar()
click.echo() if c == 'y':
click.echo('We will go on') elif c == 'n':
click.echo('Abort!') else:
click.echo('Invalid input :(')
2.2.6 等待按鍵
在 Windows 的 cmd 中我們經(jīng)??吹疆攬?zhí)行完一個命令后,提示按下任意鍵退出。通過使用 pause() 可以實現(xiàn)暫停直至用戶按下任意鍵:
import click
click.pause()
2.2.7 啟動編輯器
通過 edit() 可以自動啟動編輯器。這在需要用戶輸入多行內(nèi)容時十分有用。
在下面的示例中,會啟動默認的文本編輯器,并在里面輸入一段話:
import click def get_commit_message(): MARKER = '# Everything below is ignored\n' message = click.edit('\n\n' + MARKER) if message is not None: return message.split(MARKER, 1)[0].rstrip('\n')
edit()函數(shù)還支持打開特定文件,比如:
import click
click.edit(filename='/etc/passwd')
2.2.8 啟動應(yīng)用程序
通過 launch 可以打開 URL 或文件類型所關(guān)聯(lián)的默認應(yīng)用程序。如果設(shè)置 locate=True,則可以啟動文件管理器并自動選中特定文件。
示例:
# 打開瀏覽器,訪問 URL click.launch("https://click.palletsprojects.com/") # 使用默認應(yīng)用程序打開 txt 文件 click.launch("/my/downloaded/file.txt") # 打開文件管理器,并自動選中 file.txt click.launch("/my/downloaded/file.txt", locate=True)
2.2.9 顯示進度條
click內(nèi)置了 progressbar() 函數(shù)來方便地顯示進度條。
它的用法也很簡單,假定你有一個要處理的可迭代對象,處理完每一項就要輸出一下進度,那么就有兩種用法。
用法一:使用 progressbar構(gòu)造出 bar對象,迭代 bar對象來自動告知進度:
import time import click
all_the_users_to_process = ['a', 'b', 'c'] def modify_the_user(user): time.sleep(0.5) with click.progressbar(all_the_users_to_process) as bar: for user in bar:
modify_the_user(user)
用法二:使用 progressbar構(gòu)造出 bar對象,迭代原始可迭代對象,并不斷向 bar更新進度:
import time import click
all_the_users_to_process = ['a', 'b', 'c'] def modify_the_user(user): time.sleep(0.5) with click.progressbar(all_the_users_to_process) as bar: for user in enumerate(all_the_users_to_process):
modify_the_user(user)
bar.update(1)
2.2.10 更多實用工具
-
打印文件名
-
標準流
-
智能打開文件
-
查找應(yīng)用程序文件夾
三、總結(jié)
click提供了非常多的增強型功能,本文著重介紹了它的 Bash 補全和十多個實用工具,這會讓你在實現(xiàn)命令行的過程中如虎添翼。此外,click還提供了諸如命令別名、參數(shù)修改、標準化令牌、調(diào)用其他命令、回調(diào)順序等諸多高級模式 以應(yīng)對更加復雜或特定的場景,我們就不再深入介紹。