目次
- 目次
- はじめに
- コマンドラインオプションツール argparseの使い方
- コマンドラインツール作成用ライブラリClick
- Pythonからシェルコマンドを実行する方法
- シェルの標準出力に色を付けて文字列を出力する方法
- 参考資料
- MyEnigma Supporters
はじめに
データ解析の時など、
コマンドラインツールを作りたくなることがあります。
自分だけが、その時だけ使う場合は、
適当にスクリプトファイルを作れば良いですが、
他人に使ってもらったり、
長い期間使用して、メンテする場合は、
ちゃんとコマンドラインツールとして作っておくと
コードの寿命が長くなると思います。
pythonにはそのような
自作コマンドラインツールを作るツールなどが、
豊富に準備されているので、
今回はそれらのツールを使った
pythonコマンドラインツールの作り方について説明したいと思います。
コマンドラインオプションツール argparseの使い方
pythonのデフォルトモジュールである
argparseは、コマンドラインツールに
重要なコマンドラインオプションのパーサモジュールです。
unixのツールによくあるハイフン+記号のオプション
のようなオプション指定のシステムと、
その使い方を示したヘルプを自動生成してくれます。
argparseのサンプルプログラム
下記はargparseのサンプルプログラムです。
#!/usr/bin/env python # -*- coding: utf-8 -*-:q import argparse parser = argparse.ArgumentParser(description='argparse sample.') #bool オプション parser.add_argument('-e','--error', action='store_true', default=False, help='show error (default: show no error)') #数値 オプション parser.add_argument('-d','--data', type=int, help='data number') #文字列オプション parser.add_argument('-s','--str', type=str, help='data name') args = parser.parse_args() print args
argparseは大きく分けて3つの処理に分けられれるため、
それぞれの処理について説明します。
1 パーサの生成
まずはじめに下記のように、argparseをインポートして、
コマンドラインオプション用のパーサを作ります。
引数のdescriptionは、後述するヘルプ表示をした時の、
スクリプトの概要説明文になります。
import argparse parser = argparse.ArgumentParser(description='argparse sample.')
2 コマンドラインオプションの追加
続いて、使用するコマンドラインオプションを追加します。
boolや数値、文字列など、基本的なデータを
コマンドラインオプション経由で指定することができます。
bool型のオプション
下記のように設定することで、bool型のオプションを設定できます。
parser.add_argument('-e','--error', action='store_true', default=False, help='show error (default: show no error)')
上記のコードの場合、-eを付けることでerrorという変数をTrueにすることができます。
-eをつけた時に、errorをFalseにしたい場合は、action='store_false'とします。
defaultはオプションを指定しなかった時のerrorの値です。
helpは後述のようにヘルプを表示させた時の、
オプションの説明になります。
下記のようにオプションを指定することで
error変数がTrueになっているのがわかります。
$ python argparseSample.py -e
Namespace(data=None, error=True, str=None)
数値型のオプション
下記は数値オプションです。
parser.add_argument('-d','--data', type=int, help='data number')
type引数に型を指定することで、
下記のように型以外の引数を与えた時にエラーを返してくれます。
$ python argparseSample.py -d 20.0
usage: argparseSample.py [-h] [-e] [-d DATA]
文字列型のオプション
最後がコマンドラインオプションのパース文です。
parser.add_argument('-s','--str', type=str, help='data name')
基本的に先ほどの数値と同じです。
下記のように使用できます。
$ python argparseSample.py -s hoge
Namespace(data=None, error=False, str='hoge')
3. コマンドラインオプションのパース
最後は受け取ったコマンドラインオプションをパースします。
args = parser.parse_args()
args変数の要素として、
args.errorやargs.data、args.strが格納され、
コードに使用することができます。
ヘルプの表示
argparseの素晴らしい所は
コマンドラインツールのヘルプを自動生成してくれる所です。
先ほどのサンプルコードを-hのオプションを指定すると、
下記のようにヘルプが表示されます。
$python argparseSample.py -h
usage: argparseSample.py [-h] [-e] [-d DATA] [-s STR]
argparse sample.
optional arguments:
-h, --help show this help message and exit
-e, --error show error (default: show no error)
-d DATA, --data DATA data number
-s STR, --str STR data name
コードをドキュメント化出来て、
すごく便利ですね。
コマンドラインツール作成用ライブラリClick
argparseはデフォルトでPythonにバンドルされているので、
使いやすいですが、Clickというライブラリを使いことで、
簡単にデコレータを使って、関数をコマンドラインツール化できます。
下記の記事のように、setup.pyを設定することで簡単に
pipでインストールするようにパッケージ化が可能です。
こちらのリポジトリは、非常に簡単なサブコマンドを持つCLIツールのサンプルです。
下記のように、シェル補完も可能です。
こちらの3rd partyライブラリを使うと、
コマンドラインからロガーのレベルを変更することができます。
clickで作ったツールのテスト方法
venvを使って、仮想環境を作ることでかんたんにテストできます。
$ python -m venv venv
$ source venv/bin/activate
$ pip install --editable .
Pythonからシェルコマンドを実行する方法
コマンドラインツールを作っていると、
すべてpythonでやるのではなく、
シェルコマンドを使って、
ファイルの検索やコピー、削除などをしたくなります。
そこで自作のpythonコードからシェルコマンドを駆使する方法を説明します。
pythonからシェルコマンドを利用する場合は、
osモジュールを使う方法がかつては一般的でしたが、
osモジュールは将来的に廃止される予定らしいので、
現在はsubprocessというモジュールを使います。
このsubprcessは新しいプロセスを生成して処理を実行する
pythonのデフォルトモジュールです。
subprocessを使ってシェルコマンドを実行する方法は
下記のようにいくつかあります。
call関数 シェルコマンドを実行する
シェルコマンドを実行するのみなら、
call関数が便利です。
引数にシェルコマンドを文字列として指定し、
shell=Trueとすればコマンドを実行してくれます。
コマンドが終了するまで待つようになるので注意しましょう。
import subprocess cmd = "ls" subprocess.call( cmd, shell=True )
check_output関数 シェルコマンドの返り値を利用する
シェルコマンドの返り値を利用したい場合は、
check_output関数を使います。
import subprocess cmd = "ls" ret=subprocess.check_output( cmd, shell=True ) print ret
check_call関数 シェルコマンドの終了を待つ
シェルコマンドの処理が終わったことをチェックしたい場合は
check_call関数を使います。
無事コマンドが終了すれば、返り値は0になるはずです。
エラーの場合は、CalledProcessError例外が出されます。
import subprocess cmd = "ls" ret = subprocess.check_call( cmd ) print ret
Popen:プロセスの終了を待たずに複数処理を並列実行する
上記のサンプルでは、
一つのプロセスが終わるまで
次の処理を行えませんでしたが、
下記の記事でかいたとおり、
Popenを使うことで、
別プロセスで処理を実行させつつ、
別の処理を実施することができます。
例えば重い処理をマルチコアの有効性を利用して
同時処理したい場合は、
下記のサンプルのように、
Popenを使って複数の処理を並列実行することができます。
import subprocess subprocess.Popen("hoge 1",shell=True) subprocess.Popen("hoge 2",shell=True) subprocess.Popen("hoge 3",shell=True)
シェルの標準出力に色を付けて文字列を出力する方法
コマンドラインツールを作っていると、
エラーやワーニングの情報をユーザに伝えるために、
出力結果の文字に色を付けたくなることがあります。
そんな時は、下記のようにprint文の冒頭と末尾に
フォーマッティングの文字を挿入すれば、
文字に色を付けることができます。
しかし、上記のようにフォーマットをするのは面倒なので、
簡単に文字列に色を付けて文字を標準出力できる
モジュールを作りました。
下記のモジュールを保存して、
Print関数を使うことで、
冒頭のような色付きの文字列を表示させることができます。
使い方は、main文の中をみればすぐにわかると思います。
#!/usr/bin/env python # -*- coding: utf-8 -*- # author:Atsushi Sakai # license: MIT def Print(string, color, highlight=False): u""" Colored print colorlist: red,green,yellow,blue,magenta,cyan,white,crimson """ end="\033[1;m" pstr="" if color == "red": if highlight: pstr+='\033[1;41m' else: pstr+='\033[1;31m' elif color == "green": if highlight: pstr+='\033[1;42m' else: pstr+='\033[1;32m' elif color == "yellow": if highlight: pstr+='\033[1;43m' else: pstr+='\033[1;33m' elif color == "blue": if highlight: pstr+='\033[1;44m' else: pstr+='\033[1;34m' elif color == "magenta": if highlight: pstr+='\033[1;45m' else: pstr+='\033[1;35m' elif color == "cyan": if highlight: pstr+='\033[1;46m' else: pstr+='\033[1;36m' elif color == "white": if highlight: pstr+='\033[1;47m' else: pstr+='\033[1;37m' elif color == "crimson": if highlight: pstr+='\033[1;48m' else: pstr+='\033[1;38m' else: print("Error Unsupported color:"+color) print(pstr+string+end) if __name__ == '__main__': Print("Red","red") Print("Green","green") Print("Yellow","yellow") Print("Blue","blue") Print("Magenta","magenta") Print("Cyan","cyan") Print("White","white") Print("Crimson","crimson") Print("Highlited Red","red",highlight=True) Print("Highlited Green","green",highlight=True) Print("Highlited Yellow","yellow",highlight=True) Print("Highlited blue","blue",highlight=True) Print("Highlited Magenta","magenta",highlight=True) Print("Highlited Cyan","cyan",highlight=True) Print("Highlited Crimson","crimson",highlight=True)
参考資料
MyEnigma Supporters
もしこの記事が参考になり、
ブログをサポートしたいと思われた方は、
こちらからよろしくお願いします。