コマンドラインに-vオプションを追加して、さまざまな詳細レベルを指定できるようにしたいと思います。例えば:
$ myprogram.py
$ myprogram.py -v
$ myprogram.py -vv
$ myprogram.py -v -v -v
それぞれ、verbose = 0、verbose = 1、verbose = 2、verbose = 3になります。 argparseを使用してそれをどのように達成できますか?
オプションで、次のように指定できると便利です。
$ myprogram -v 2
これは、nargs='?'
(-v
フラグの後に0または1の引数を受け入れる)とカスタムアクション(0または1の引数を処理する)を使用して行うことができます。
import sys
import argparse
class VAction(argparse.Action):
def __init__(self, option_strings, dest, nargs=None, const=None,
default=None, type=None, choices=None, required=False,
help=None, metavar=None):
super(VAction, self).__init__(option_strings, dest, nargs, const,
default, type, choices, required,
help, metavar)
self.values = 0
def __call__(self, parser, args, values, option_string=None):
# print('values: {v!r}'.format(v=values))
if values is None:
self.values += 1
else:
try:
self.values = int(values)
except ValueError:
self.values = values.count('v')+1
setattr(args, self.dest, self.values)
# test from the command line
parser = argparse.ArgumentParser()
parser.add_argument('-v', nargs='?', action=VAction, dest='verbose')
args = parser.parse_args()
print('{} --> {}'.format(sys.argv[1:], args))
print('-'*80)
for test in ['-v', '-v -v', '-v -v -v', '-vv', '-vvv', '-v 2']:
parser = argparse.ArgumentParser()
parser.add_argument('-v', nargs='?', action=VAction, dest='verbose')
args=parser.parse_args([test])
print('{:10} --> {}'.format(test, args))
コマンドラインからscript.py -v -v
を実行すると、次のようになります。
['-v', '-v'] --> Namespace(verbose=2)
--------------------------------------------------------------------------------
-v --> Namespace(verbose=1)
-v -v --> Namespace(verbose=2)
-v -v -v --> Namespace(verbose=3)
-vv --> Namespace(verbose=2)
-vvv --> Namespace(verbose=3)
-v 2 --> Namespace(verbose=2)
Printステートメントのコメントを解除して、VAction
の動作を確認します。
argparseは action='count'
をサポートします:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('-v', '--verbose', action='count', default=0)
for c in ['', '-v', '-v -v', '-vv', '-vv -v', '-v -v --verbose -vvvv']:
print(parser.parse_args(c.split()))
出力:
Namespace(verbose=0)
Namespace(verbose=1)
Namespace(verbose=2)
Namespace(verbose=2)
Namespace(verbose=3)
Namespace(verbose=7)
None
ではなく冗長レベル0を与えるためにdefault=0
引数が必要ない場合は、-v
を明示的に設定する必要があります。
質問の最初の部分はappend_const
で処理できます。そうでなければ、罰金で提案されているように、おそらくカスタムアクションを書くのに行き詰まっています nutbuによる回答 。
import argparse
ap = argparse.ArgumentParser()
ap.add_argument('-v', action = 'append_const', const = 1)
for c in ['', '-v', '-v -v', '-vv', '-vv -v']:
opt = ap.parse_args(c.split())
opt.v = 0 if opt.v is None else sum(opt.v)
print opt
出力:
Namespace(v=0)
Namespace(v=1)
Namespace(v=2)
Namespace(v=2)
Namespace(v=3)
Unutbuの答えを拡張して、-quiet/-qの組み合わせの処理を含むカスタムアクションを次に示します。これはPython3でテストされています。 Python> = 2.7で使用することは大したことではありません。
_class ActionVerbose(argparse.Action):
def __call__(self, parser, args, values, option_string=None):
#print(parser, args, values, option_string)
# Obtain previously set value in case this option call is incr/decr only
if args.verbose == None:
base = 0
else:
base = args.verbose
# One incr/decr is determined in name of option in use (--quiet/-q/-v/--verbose)
option_string = option_string.lstrip('-')
if option_string[0] == 'q':
incr = -1
Elif option_string[0] == 'v':
incr = 1
else:
raise argparse.ArgumentError(self,
'Option string for verbosity must start with v(erbose) or q(uiet)')
# Determine if option only or values provided
if values==None:
values = base + incr
else:
# Values might be an absolute integer verbosity level or more 'q'/'v' combinations
try:
values = int(values)
except ValueError:
values = values.lower()
if not re.match('^[vq]+$', values):
raise argparse.ArgumentError(self,
"Option string for -v/-q must contain only further 'v'/'q' letters")
values = base + incr + values.count('v') - values.count('q')
setattr(args, self.dest, values)
@classmethod
def add_to_parser(cls,
parser, dest='verbose', default=0,
help_detail='(0:errors, 1:info, 2:debug)'):
parser.add_argument('--verbose', nargs='?', action=ActionVerbose, dest=dest, metavar='level',
default=default,
help='Increase or set level of verbosity {}'.format(help_detail))
parser.add_argument('-v', nargs='?', action=ActionVerbose, dest=dest, metavar='level',
help='Increase or set level of verbosity')
parser.add_argument('--quiet', nargs='?', action=ActionVerbose, dest=dest, metavar='level',
help='Decrease or set level of verbosity')
parser.add_argument('-q', nargs='?', action=ActionVerbose, dest=dest, metavar='level',
help='Decrease or set level of verbosity')
_
_--verbose
_、_-v
_、_-q
_、_--quiet
_の4つのオプションハンドラーすべてを設定するために使用できる便利なクラスメソッドがあります。次のように使用します。
_parser = argparse.ArgumentParser()
ActionVerbose.add_to_parser(parser, default=defaults['verbose'])
# add more arguments here with: parser.add_argument(...)
args = parser.parse_args()
_
これらの引数を持つスクリプトを使用する場合、次のことができます。
_./script -vvvvvv -v 4 -v 0 -v -vvv --verbose --quiet 2 -v qqvvqvv
_
このコマンドラインでは、_args.verbose
_は_4
_になります。
-v/-q/--verbose/--quiet
_は、その指定された番号(=冗長レベル)に対する_args.verbose
_のハードで絶対的なセットです。-v/--verbose
_は、そのレベルの増分です。-q/--quiet
_は、そのレベルのデクリメントです。-v/-q
_は、すぐにさらに_v/q
_文字でフォローアップでき、結果のレベルはthe old level + sum(count('v')) - sum(count('q'))
になります。別の動作が必要な場合に備えて、カスタムアクションはかなり簡単に変更できるはずです。たとえば、_--quiet
_がレベルを0、さらには-1にリセットすることを好む人もいます。このためには、_-q
_と_--quiet
_のadd_argumentからnargs
を削除し、ハードコードして_value = 0
_ _if option_string[0] == 'q'
_を設定します。
使用法が間違っている場合、適切なパーサーエラーが適切に出力されます。
_./script -vvvvvv -v 4 -v 0 -v -vvv --verbose --quiet 2 -v qqvvqvav
usage: script [-h] [--verbose [level]]
[-v [level]] [--quiet [level]] [-q [level]]
script: error: argument -v: Option string for -v/-q must contain only further 'v'/'q' letters
_
これは、新しいクラスを使用せず、Python 2と3の両方で機能し、「-v」/「-verbose」と「-verbose」を使用したデフォルトからの相対調整をサポートする」という私の見解です。 -q "/"-quiet "、ただしサポートしていません数字の使用をサポートします。例:"-v 2 ":
#!/usr/bin/env python
import argparse
import logging
import sys
LOG_LEVELS = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
DEFAULT_LOG_LEVEL = "INFO"
def main(argv):
parser = argparse.ArgumentParser()
parser.add_argument(
"--verbose", "-v",
dest="log_level",
action="append_const",
const=1,
)
parser.add_argument(
"--quiet", "-q",
dest="log_level",
action="append_const",
const=-1,
)
args = parser.parse_args(argv[1:])
log_level = LOG_LEVELS.index(DEFAULT_LOG_LEVEL)
# For each "-q" and "-v" flag, adjust the logging verbosity accordingly
# making sure to clamp off the value from 0 to 4, inclusive of both
for adjustment in args.log_level or ():
log_level = min(len(LOG_LEVELS) - 1, max(log_level + adjustment, 0))
log_level_name = LOG_LEVELS[log_level]
print(log_level_name)
logging.getLogger().setLevel(log_level_name)
if __name__ == "__main__":
main(sys.argv)
例:
$ python2 verbosity.py -vvv
DEBUG
$ python3 verbosity.py -vvv -q
INFO
$ python2 verbosity.py -qqq -vvv -q
WARNING
$ python2 verbosity.py -qqq
CRITICAL
argparse
は、複数の引数を指定できるappend
アクションをサポートします。チェック http://docs.python.org/library/argparse.html 、「append
」を検索します。
最初に提案された方法は、混乱する可能性が高くなります。さまざまなレベルの詳細度に対するさまざまなオプション名、またはオプションで詳細度のレベルの数値インジケータが後に続く1つの詳細度フラグは、ユーザーを混乱させる可能性が低く、詳細度レベルをより柔軟に割り当てることができます。