ちょっとしたコマンドラインツールを作るとき、欲しくなるのが以下のようなカッコイイオプション指定機能とヘルプ表示。
$ python photosort.py -h usage: photosort.py [-h] [-d [PATH_ROOT_DST]] [-p SORT_PHOTO_EXTENTIONS [SORT_PHOTO_EXTENTIONS ...]] [-v SORT_VIDEO_EXTENTIONS [SORT_VIDEO_EXTENTIONS ...]] [-l DELIMITER] [--subdir-year] [--subdir-month] [--copy] [--callback-function CALLBACK_FUNCTION] [--debug DEBUG] path_root_src This script to make directory of date which the photo is taken, and move the photo into the directory. positional arguments: path_root_src Directory path where your taken photo files are located. optional arguments: -h, --help show this help message and exit -d [PATH_ROOT_DST], --path-root-dst [PATH_ROOT_DST] Directory path where you want to create date folder and locate photo files. (default: same as source directory) -p SORT_PHOTO_EXTENTIONS [SORT_PHOTO_EXTENTIONS ...], --sort-photo-extentions SORT_PHOTO_EXTENTIONS [SORT_PHOTO_EXTENTIONS ...] Extentions of photo file which you want to sort. (default: jpg) -v SORT_VIDEO_EXTENTIONS [SORT_VIDEO_EXTENTIONS ...], --sort-video-extentions SORT_VIDEO_EXTENTIONS [SORT_VIDEO_EXTENTIONS ...] Extentions of video file which you want to sort. (default: jpg) -l DELIMITER, --delimiter DELIMITER A character as delimiter which you want to set the name of date folder like "2014-05-01". (default: none) --subdir-year Generate sub directory of year if this is set. --subdir-month Generate sub directory of month if this is set. --copy Copy media files but not move. --callback-function CALLBACK_FUNCTION Function to be callback when copying/moving a photo finished. The format is like "/User/takashi/flickr_upl oader/flickr_uploader:upload?key=xxx¶m=yyy". The "upload" function should have an argument "path_to_photo_uploading" as first and another args is passed to keyword arguments. (default: none) --debug DEBUG debug mode if this flag is set (default: info)
pythonなら、標準パッケージargparseを使うことで、簡単に実装できます。
スクリプトの引数仕様
例えば、とあるスクリプトの引数をこんな感じで指定できるようにしたい。
- srcディレクトリパスの指定は必須
- dstディレクトリパスの指定は必須ではない
- 対象とするファイルの拡張子を複数指定したい
- debug用のprint文は普段はstdoutに出したくない
まずは初期化
ArgumentParserオブジェクトを生成します。
その初期化パラメータは、description以外はデフォルトのままで問題ありません。add_help(-h/–help オプションをパーサーに追加する)等、便利な機能は予め有効になっています。
import argparse parser = argparse.ArgumentParser(description='This script is ...')
引数の追加
その1
srcディレクトリパスの指定は必須
add_argumentの第一引数にpath_root_srcを、nargsにNoneを指定します。この名前に、-や--を付けないのがミソです。
こうすることで、-や--付オプション以外の引数がスクリプトに指定されないと、too few argument
エラーとなってくれます。
もしnargsを'?'にした場合は、引数の数0個を許可したことになるので、エラーになることなくスクリプトを実行できることになります。ただし、その際はdefaultやconstの設定が必要になります。詳しくは後ほど。parser.add_argument( 'path_root_src', action='store', nargs=None, const=None, default=None, type=str, choices=None, help='Directory path where your taken photo files are located.', metavar=None)ここで指定した第一引数の文字列'path_root_src'は、最後の仕上げでコールする
args = parser.parse_args()
が返すNamespaceオブジェクトの属性名として使用されます。
つまり、下記のように実行した場合、args.path_root_src
に""/Users/test/Pictures""が格納されることになります。$ ./photosort.py /Users/test/Picturesその2
dstディレクトリパスの指定は必須ではない
add_argumentの第一引数に2種類のオプション文字列を、nargsに'?'を指定することで実現可能です。
これにより、可能なら1つの引数がコマンドラインから取られ、args = parser.parse_args()
が返すNamespaceオブジェクトの属性名'path_root_dst'として使用され、引数の値はその属性にセットされます。
オプション引数そのものが存在しない(-d自体が指定されない)場合はdefaultの値が渡されます。
それに対し、オプション引数が指定され、その後にコマンドライン引数が無い場合は、constの値が渡されます。
下記の例の場合、どちらもNoneなので同じことですが…。parser.add_argument( '-d', '--path-root-dst', action='store', nargs='?', const=None, default=None, type=str, choices=None, help='Directory path where you want to create date folder and locate photo files. (default: same as source directory)', metavar=None)その3
対象とするファイルの拡張子を複数指定したい
add_argumentの第一引数に2種類のオプション文字列を、nargsに'+'を指定することで実現可能です。
nargsに'+'を指定すると、最低でも1つのコマンドライン引数が必要となり、条件を満たさない場合はtoo few argument
エラーとなります。
ただし、too few argument
エラーとなるのは、オプションが指定されているのにコマンドライン引数が指定されていない場合のみです。
オプション自体が指定されていない場合は、defaultに指定した['jpg']
が使用され、エラーになりません。parser.add_argument( '-e', '--sort-files-extentions', action='store', nargs='+', const=None, default=['jpg'], type=str, choices=None, help='Extentions of file which you want to sort. (default: jpg)', metavar=None)その4
debug用のprint文は普段はstdoutに出したくない
あるオプション引数が指定された場合、単純にTrueかFalseの値を持ちたい場合、actionに'store_true'や'store_false'を指定することで実現できます。
このスクリプトが--debug付きで実行された場合は、最後の仕上げでコールするargs = parser.parse_args()
が返すNamespaceオブジェクトの属性名args.debug
にTrueが格納されることになります。parser.add_argument( '--debug', action='store_true', help='debug mode if this flag is set (default: False)')最後の仕上げ
以下のようにすると、これまでに指定した引数設定を元にして、コマンドラインで指定された引数をNamespaceオブジェクトの属性に変換して返します。
import sys args = parser.parse_args(sys.argv[1:])下記のようにparse_args()関数の引数を省略しても結果は同じです。
args = parser.parse_args()こうしてできたargsオブジェクトをダンプしてみると、以下のように属性値として格納されていることがわかります。
(Pdb) b 112 Breakpoint 1 at /Users/dodo5522/Development/manage_media_data/photosort.py:112 (Pdb) c /Users/dodo5522/Development/manage_media_data/photosort.py(112)() -> args = parser.parse_args() (Pdb) n (Pdb) dir(args) ['__class__', '__contains__', '__delattr__', '__dict__', '__doc__', '__eq__', '__format__', '__getattribute__', '__hash__', '__init__', '__module__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__weakref__', '_get_args', '_get_kwargs', 'debug', 'path_root_dst', 'path_root_src', 'sort_files_extentions'] (Pdb) args.debug (Pdb) print args.debug False (Pdb) print args.path_root_dst /Users/dodo5522/Public (Pdb) print args.path_root_src /Users/dodo5522/Pictures (Pdb) print args.sort_files_extentions ['jpg', 'png', 'mov'] (Pdb)