-vvvや-qで作ったコマンドのloggingレベルを変更する斬新なコード

はじめに

argparse にcountというactionがあり、これを使うと渡した同一オプションの数をカウントすることができます。 これを使って、例えば、curlsshなどで見られる -v-vv の記述に似せたものをやろうという話です。

基本的な考え方は以下です。

  • defaultは logging.WARN
  • -v オプションは loggingレベルを下げる
  • -q オプションは loggingレベルを上げる

logging

また、logging はNOTSET,DEBUG,INFO,WARNING,ERROR,CRITICALという順にdefaultのloggingレベルが設定されています。が、これらは単なる数値です。

import logging

print(logging.NOTSET) # => 0
print(logging.DEBUG) # => 10
print(logging.INFO) # => 20
print(logging.WARNING) # => 30
print(logging.ERROR) # => 40
print(logging.CRITICAL) # => 50

argparse

argparseのcountを使って引数に渡されたvの数を数える事ができます。(http://docs.python.jp/3/library/argparse.html#action から引用)

'count' - このアクションはキーワード引数の数を数えます。例えば、verboseレベルを上げるのに役立ちます:

>>> parser = argparse.ArgumentParser()
>>> parser.add_argument('--verbose', '-v', action='count')
>>> parser.parse_args('-vvv'.split())
Namespace(verbose=3)

そんなわけで、以下のようなコードを書くと、オプションによって手軽にloggingレベルを調節できるようになります。

# -*- coding:utf-8 -*-
# program.py

import argparse
import logging
import sys

logger = logging.getLogger(__name__)

parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbose', action='count', default=0)
parser.add_argument('-q', '--quiet', action='count', default=0)
args = parser.parse_args(sys.argv[1:])

logging_level = logging.WARN + 10*args.quiet - 10*args.verbose
logging.basicConfig(level=logging_level)

logger.debug("debug")
logger.info("info")
logger.warning("warning")
logger.error("error")
logger.critical("critical")

以下の様に使えます。 -v-q も多すぎてもエラーにはなりません。

# defaultはwarning
$ python program.py
WARNING:__main__:warning
ERROR:__main__:error
CRITICAL:__main__:critical
# -vでlogging levelを下げられる
$ python program.py -vv
DEBUG:__main__:debug
INFO:__main__:info
WARNING:__main__:warning
ERROR:__main__:error
CRITICAL:__main__:critical
# -qでlogging levelを上げられる
$ python program.py -q
ERROR:__main__:error
CRITICAL:__main__:critical
# やりたければ2つを混ぜあわせても
$ python program.py -vv -q
INFO:__main__:info
WARNING:__main__:warning
ERROR:__main__:error
CRITICAL:__main__:critical
# hmm
$ python program.py -vvvvvvv
DEBUG:__main__:debug
INFO:__main__:info
WARNING:__main__:warning
ERROR:__main__:error
CRITICAL:__main__:critical

便利ですね。これは元々redditのコメントにあった内容です(https://www.reddit.com/r/Python/comments/3nctlm/what_python_tools_should_i_be_using_on_every/cvn0ybf)。

参考