Python 命令行之旅:深刻 click 之加強功能

做者:HelloGitHub- Prodesire

涉及的示例代碼和歷史文章,已同步更新到 HelloGitHub-Team 倉庫python

1、前言

在前面三篇文章中,咱們介紹了 click 中的參數、選項和命令,本文將介紹 click 錦上添花的功能,以幫助咱們更加輕鬆地打造一個更增強大的命令行程序。git

本系列文章默認使用 Python 3 做爲解釋器進行講解。
若你仍在使用 Python 2,請注意二者之間語法和庫的使用差別哦~
複製代碼

2、加強功能

2.1 Bash 補全

Bash 補全是 click 提供的一個很是便捷和強大的功能,這是它比 argpasedocopt 強大的一個表現。github

在命令行程序正確安裝後,Bash 補全才可使用。而如何安裝能夠參考 setup 集成。Click 目前僅支持 Bash 和 Zsh 的補全。shell

2.1.1 補全能力

一般來講,Bash 補全支持對子命令、選項、以及選項或參數值得補全。好比:編程

$ repo <TAB><TAB>
clone    commit   copy     delete   setuser
$ repo clone -<TAB><TAB>
--deep     --help     --rev      --shallow  -r
複製代碼

此外,click 還支持自定義補全,這在動態生成補全場景中頗有用,使用 autocompletion 參數。autocompletion 須要指定爲一個回調函數,而且返回字符串的列表。此函數接受三個參數:api

  • ctx —— 當前的 click 上下文
  • args 傳入的參數列表
  • incomplete 正在補全的詞

這裏有一個根據環境變量動態生成補全的示例:瀏覽器

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 回調函數中返回的字符串列表中的字符串改成二元元組,第一個元素是補全內容,第二個元素是幫助信息。bash

這裏有一個顏色補全的示例:app

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 的補全功能,就須要告訴它你的命令行程序有補全的能力。一般經過一個神奇的環境變量 _<PROG_NAME>_COMPLETE 來告知,其中 <PROG_NAME> 是大寫下劃線形式的程序名稱。less

好比有一個命令行程序叫作 foo-bar,那麼對應的環境變量名稱爲 _FOO_BAR_COMPLETE,而後在 .bashrc 中使用 source 導出便可:

eval "$(_FOO_BAR_COMPLETE=source foo-bar)"
複製代碼

或者在 .zshrc 中使用:

eval "$(_FOO_BAR_COMPLETE=source_zsh foo-bar)"
複製代碼

不過上面的方式老是在命令行程序啓動時調用,這可能在有多個程序時減慢 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() 函數能夠說是最有用的實用工具了。它和 Python 的 print 相似,主要的區別在於它同時在 Python 2 和 3 中生效,可以智能地檢測未配置正確的輸出流,且幾乎不會失敗(除了 Python 3 中的少數限制。)

echo 即支持 unicode,也支持二級制數據,如:

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() 函數來指定顏色:

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 還提供了更加簡便的函數 secho,它就是 echostyle 的組合:

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() 函數就能夠輕鬆作到。

例如:

def less():
    click.echo_via_pager('\n'.join('Line %d' % idx
                                   for idx in range(200)))
複製代碼

若是輸出的文本特別大,處於性能的考慮,但願翻頁時生成對應內容,那麼就可使用生成器:

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() 能夠輕鬆清除屏幕內容:

import click
click.clear()
複製代碼

2.2.5 從終端獲取字符

一般狀況下,使用內建函數 inputraw_input 得到的輸入是用戶輸出一段字符而後回車獲得的。但在有些場景下,你可能想在用戶輸入單個字符時就能獲取到而且作必定的處理,這個時候 getchar() 就派上了用場。

好比,根據輸入的 yn 作特定處理:

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 中咱們常常看到當執行完一個命令後,提示按下任意鍵退出。經過使用 pause() 能夠實現暫停直至用戶按下任意鍵:

import click
click.pause()
複製代碼

2.2.7 啓動編輯器

經過 edit() 能夠自動啓動編輯器。這在須要用戶輸入多行內容時十分有用。

在下面的示例中,會啓動默認的文本編輯器,並在裏面輸入一段話:

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() 函數還支持打開特定文件,好比:

import click
click.edit(filename='/etc/passwd')
複製代碼

2.2.8 啓動應用程序

經過 launch 能夠打開 URL 或文件類型所關聯的默認應用程序。若是設置 locate=True,則能夠啓動文件管理器並自動選中特定文件。

示例:

# 打開瀏覽器,訪問 URL
click.launch("https://click.palletsprojects.com/")

# 使用默認應用程序打開 txt 文件
click.launch("/my/downloaded/file.txt")

# 打開文件管理器,並自動選中 file.txt
click.launch("/my/downloaded/file.txt", locate=True)
複製代碼

2.2.9 顯示進度條

click 內置了 progressbar() 函數來方便地顯示進度條。

它的用法也很簡單,假定你有一個要處理的可迭代對象,處理完每一項就要輸出一下進度,那麼就有兩種用法。

用法一:使用 progressbar 構造出 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 構造出 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 更多實用工具

3、總結

click 提供了很是多的加強型功能,本文着重介紹了它的 Bash 補全和十多個實用工具,這會讓你在實現命令行的過程當中如虎添翼。此外,click 還提供了諸如命令別名、參數修改、標準化令牌、調用其餘命令、回調順序等諸多高級模式 以應對更加複雜或特定的場景,咱們就再也不深刻介紹。

click 的介紹就告一段落,它將會是你編寫命令行程序的一大利器。在下一篇文章中,咱們依然會經過實現一個簡單的 git 程序來進行 click 的實戰。


抽獎活動HG 聯合掘金社區舉辦的抽獎活動,獎品爲掘金贊助的該社區周邊:各類大禮包、新款衛衣。獎品共計 10 份,獎品多多。抽獎絕緣體的小夥伴能夠試一試,這多是你離中獎最近的一次

微博抽獎活動傳送門


『講解開源項目系列』——讓對開源項目感興趣的人再也不畏懼、讓開源項目的發起者再也不孤單。跟着咱們的文章,你會發現編程的樂趣、使用和發現參與開源項目如此簡單。歡迎留言聯繫咱們、加入咱們,讓更多人愛上開源、貢獻開源~

相關文章
相關標籤/搜索