Python命令行之旅:使用argparse实现git命令
前言
本文將以我們?nèi)粘9ぷ髦凶畛R姷膅it命令為例,講解如何使用argparse庫(kù)來(lái)實(shí)現(xiàn)一個(gè)真正可用的命令行程序。
- 本文默認(rèn)使用 Python 3 作為解釋器進(jìn)行講解。
- 若你仍在使用 Python 2,請(qǐng)注意兩者之間語(yǔ)法和庫(kù)的使用差異哦~
git常用命令
大家不妨回憶一下,平時(shí)最常使用git子命令都有哪些?
當(dāng)你寫好一段代碼或增刪一些文件后,會(huì)用如下命令查看文件狀態(tài):
git status確認(rèn)文件狀態(tài)后,會(huì)用如下命令將的一個(gè)或多個(gè)文件(夾)添加到暫存區(qū):
git add [pathspec [pathspec ...]]然后使用如下命令提交信息:
git commit -m "your commit message"最后使用如下命令將提交推送到遠(yuǎn)程倉(cāng)庫(kù):
git push我們將使用argparse和gitpython庫(kù)來(lái)實(shí)現(xiàn)這4個(gè)子命令。
關(guān)于gitpython
gitpython [1]是一個(gè)和git倉(cāng)庫(kù)交互的Python第三方庫(kù)。我們將借用它的能力來(lái)實(shí)現(xiàn)真正的git邏輯。
安裝:
pip install gitpython思考
在實(shí)現(xiàn)前,我們不妨礙先思考下會(huì)用到argparse的某些功能?整個(gè)程序的結(jié)構(gòu)是怎樣的?
argparse
-
要實(shí)現(xiàn)子命令,那么之前介紹到的嵌套解析器必不可少
-
當(dāng)用戶鍵入子命令時(shí),子命令所對(duì)應(yīng)的子解析器需要作出響應(yīng),那么需要用到子解析器的set_defaults功能
-
針對(duì)git add [pathspec [pathspec …]],我們需要實(shí)現(xiàn)位置參數(shù),而且數(shù)量是任意個(gè)
-
針對(duì)git commit --message msg或git commit -m msg,我們需要實(shí)現(xiàn)選項(xiàng)參數(shù),并且可以長(zhǎng)選項(xiàng),又可短選項(xiàng)
程序結(jié)構(gòu)
-
命令行程序需要一個(gè)cli函數(shù)來(lái)作為統(tǒng)一的入口,它負(fù)責(zé)合并解析器,并解析命令行參數(shù)
-
我們還需要四個(gè)handle_xxx函數(shù)響應(yīng)對(duì)應(yīng)的子命令
則基本結(jié)構(gòu)如下:
''' 遇到問(wèn)題沒(méi)人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:857662006 尋找有志同道合的小伙伴, 互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書! ''' import os import argparse from git.cmd import Gitdef cli():"""git 命名程序入口"""passdef handle_status(git, args):"""處理 status 命令"""passdef handle_add(git, args):"""處理 add 命令"""passdef handle_commit(git, args):"""處理 -m <msg> 命令"""passdef handle_push(git, args):"""處理 push 命令"""passif __name__ == '__main__':cli()下面我們將一步步地實(shí)現(xiàn)我們的git程序。
實(shí)現(xiàn)
預(yù)先我們?cè)赼rgparse-git.py [2]文件中實(shí)現(xiàn)我們的git程序。
構(gòu)建解析器
我們需要整合一個(gè)父解析器,作為程序的根解析器,程序名稱指定為git。然后在上面添加子解析器,為后續(xù)的子命令的解析做準(zhǔn)備:
狀態(tài)子命令
我們需要在cli函數(shù)中添加一個(gè)用于解析status命令的子解析器status_parser,并指定其對(duì)應(yīng)的處理函數(shù)為handle_status。
需要說(shuō)明的是,在status_parser.set_defaults函數(shù)中,能接收任意名稱的關(guān)鍵字參數(shù),這個(gè)參數(shù)值會(huì)存放于父解析器解析命令行參數(shù)后的變量中。
例如,在此示例程序中,我們?yōu)槊總€(gè)子解析器定義了handle,那么args = parser.parse_args()中的args將具有handle屬性,我們可以引用不同的子命令,那么這個(gè)handle就是不同的響應(yīng)函數(shù)。
定義了status的子解析器后,我們?cè)賹?shí)現(xiàn)下handle_status即可實(shí)現(xiàn)status命令的響應(yīng):
def handle_status(git, args):"""處理 status 命令"""cmd = ['git', 'status']output = git.execute(cmd)print(output)不尖銳出,我們最后調(diào)用了真正的git status來(lái)實(shí)現(xiàn),并打印了輸出。
可能你會(huì)對(duì)handle_status的函數(shù)簽名感到困惑,的這里git狀語(yǔ)從句:args的英文怎么傳入的呢?這其實(shí)是由我們自己控制的,將在本文最后講解。
添加子命令
同樣,我們需要在cli函數(shù)中添加一個(gè)用于解析add命令的子解析器add_parser,并指定其對(duì)應(yīng)的處理函數(shù)為handle_add。
額外要做的是,要在子解析器add_parser上添加一個(gè)pathspec位置參數(shù),且其數(shù)量是任意的:
''' 遇到問(wèn)題沒(méi)人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:857662006 尋找有志同道合的小伙伴, 互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書! ''' def cli():...# addadd_parser = subparsers.add_parser('add',help='Add file contents to the index')add_parser.add_argument('pathspec',help='Files to add content from',nargs='*')add_parser.set_defaults(handle=handle_add)然后,就是實(shí)現(xiàn)handle_add函數(shù),我們需要用到表示文件路徑的args.pathspec:
def handle_add(git, args):"""處理 add 命令"""cmd = ['git', 'add'] + args.pathspecoutput = git.execute(cmd)print(output)提交子命令
同樣,我們需要在cli函數(shù)中添加一個(gè)用于解析commit命令的子解析器commit_parser,并指定其對(duì)應(yīng)的處理函數(shù)為handle_commit。
額外要做的是,要在子解析器commit_parser上添加一個(gè)-m/ --message選項(xiàng)參數(shù),且要求必填:
''' 遇到問(wèn)題沒(méi)人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:857662006 尋找有志同道合的小伙伴, 互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書! ''' def cli():...# commitcommit_parser = subparsers.add_parser('commit',help='Record changes to the repository')commit_parser.add_argument('--message', '-m',help='Use the given <msg> as the commit message',metavar='msg',required=True)commit_parser.set_defaults(handle=handle_commit)然后,就是實(shí)現(xiàn)handle_commit函數(shù),我們需要用到表示提交信息的args.message:
def handle_commit(git, args):"""處理 -m <msg> 命令"""cmd = ['git', 'commit', '-m', args.message]output = git.execute(cmd)print(output)推子命令
同樣,我們需要在cli函數(shù)中添加一個(gè)用于解析push命令的子解析器push_parser,并指定其對(duì)應(yīng)的處理函數(shù)為handle_push。
它同status子命令的實(shí)現(xiàn)方式一致:
''' 遇到問(wèn)題沒(méi)人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:857662006 尋找有志同道合的小伙伴, 互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書! ''' def cli():...# pushpush_parser = subparsers.add_parser('push',help='Update remote refs along with associated objects')push_parser.set_defaults(handle=handle_push)然后,就是實(shí)現(xiàn)handle_push函數(shù),和handle_status類似:
def handle_push(git, args):cmd = ['git', 'push']output = git.execute(cmd)print(output)解析參數(shù)
在定義完父子解析器,并添加參數(shù)后,我們就需要對(duì)參數(shù)做解析,從而工作也是實(shí)現(xiàn)在cli函數(shù)中:
-
通過(guò)git.cmd.Git實(shí)例化出git對(duì)象,用來(lái)和git倉(cāng)庫(kù)互動(dòng)
-
通過(guò)parser.parse_args()解析命令行
-
通過(guò)hasattr(args, ‘handle’)判斷是否輸入了子命令。
-
由于每個(gè)子解析器都定義了handle,那么如果當(dāng)用戶在命令行不輸入任何命令時(shí),args就沒(méi)有handle屬性,那么我們就輸出幫助信息
-
如果用戶輸入了子命令,那么就調(diào)用args.handle,引用git和args對(duì)象,進(jìn)行處理對(duì)應(yīng)命令
-
至此,我們就實(shí)現(xiàn)了一個(gè)簡(jiǎn)單的git命令行,使用python argparse-git.py -h查看幫助如下:
''' 遇到問(wèn)題沒(méi)人解答?小編創(chuàng)建了一個(gè)Python學(xué)習(xí)交流QQ群:857662006 尋找有志同道合的小伙伴, 互幫互助,群里還有不錯(cuò)的視頻學(xué)習(xí)教程和PDF電子書! ''' usage: git [-h] command ...optional arguments:-h, --help show this help message and exitThese are common Git commands used in various situations:commandstatus Show the working tree statusadd Add file contents to the indexcommit Record changes to the repositorypush Update remote refs along with associated objects然后我們就可以愉快地使用親手打造的git程序啦!
小結(jié)
本文簡(jiǎn)單介紹了日常工作中常用的git命令,然后提出實(shí)現(xiàn)它的思路,最終一步步使用argparse和gitpython實(shí)現(xiàn)了git程序。是不是很有成就感呢?
你是否想過(guò),argparse的四步曲雖然理解簡(jiǎn)單,但略微麻煩。有沒(méi)有更簡(jiǎn)單的方式?如果我很熟悉命令行幫助語(yǔ)法,我能不能寫個(gè)幫助字符串就把所有的命令行元信息給定義出來(lái)?然后就直接輕松輕松地地獲取解析后的參數(shù)信息呢?
總結(jié)
以上是生活随笔為你收集整理的Python命令行之旅:使用argparse实现git命令的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 30段极简Python代码:这些小技巧你
- 下一篇: Python 常见优化技巧,让你的程序溜