デフォルトのサブコマンド、またはArgparseを使用したサブコマンドの処理
-
28-10-2019 - |
質問
どのようにしてデフォルトを作成できますか サブコマンド, 、またはサブコマンドが使用されていない場合を処理します argparse
?
import argparse
a = argparse.ArgumentParser()
b = a.add_subparsers()
b.add_parser('hi')
a.parse_args()
ここでは、コマンドを選択するか、次に最高レベルのパーサー(この場合はトップレベルパーサー)にのみ基づいて処理される議論を希望します。
joiner@X:~/src> python3 default_subcommand.py usage: default_subcommand.py [-h] {hi} ... default_subcommand.py: error: too few arguments
解決 2
最終的に自分で解決策につまずいたようです。
コマンドがオプションの場合は、 これにより、コマンドがオプションになります. 。元のパーサー構成には、aがありました package
可能なさまざまな手順を実行する可能性のあるコマンド、または何も与えられなかった場合、すべての手順を実行します。これにより、ステップが選択されます。
parser = argparse.ArgumentParser()
command_parser = subparsers.add_parser('command')
command_parser.add_argument('--step', choices=['prepare', 'configure', 'compile', 'stage', 'package'])
...other command parsers
parsed_args = parser.parse_args()
if parsed_args.step is None:
do all the steps...
他のヒント
Python 3.2(および2.7)では、3.3と3.4(応答なし)ではなく、そのエラーが発生します。したがって、3.3/3.4でテストできます parsed_args
空になること Namespace
.
より一般的な解決策は、メソッドを追加することです set_default_subparser()
(から取られます ruamel.std.argparse パッケージ)とそのメソッドを直前に呼び出します parse_args()
:
import argparse
import sys
def set_default_subparser(self, name, args=None, positional_args=0):
"""default subparser selection. Call after setup, just before parse_args()
name: is the name of the subparser to call by default
args: if set is the argument list handed to parse_args()
, tested with 2.7, 3.2, 3.3, 3.4
it works with 2.6 assuming argparse is installed
"""
subparser_found = False
for arg in sys.argv[1:]:
if arg in ['-h', '--help']: # global help if no subparser
break
else:
for x in self._subparsers._actions:
if not isinstance(x, argparse._SubParsersAction):
continue
for sp_name in x._name_parser_map.keys():
if sp_name in sys.argv[1:]:
subparser_found = True
if not subparser_found:
# insert default in last position before global positional
# arguments, this implies no global options are specified after
# first positional argument
if args is None:
sys.argv.insert(len(sys.argv) - positional_args, name)
else:
args.insert(len(args) - positional_args, name)
argparse.ArgumentParser.set_default_subparser = set_default_subparser
def do_hi():
print('inside hi')
a = argparse.ArgumentParser()
b = a.add_subparsers()
sp = b.add_parser('hi')
sp.set_defaults(func=do_hi)
a.set_default_subparser('hi')
parsed_args = a.parse_args()
if hasattr(parsed_args, 'func'):
parsed_args.func()
これは2.6で動作します(if argparse
Pypiからインストールされています)、2.7、3.2、3.3、3.4。そして、両方を行うことができます
python3 default_subcommand.py
と
python3 default_subcommand.py hi
同じ効果で。
既存のものの1つではなく、デフォルト用に新しいサブパーサーを選択することができます。
コードの最初のバージョンでは、以前に定義されたサブパーサーの1つをデフォルトのものとして設定できます。以下の変更により、新しいデフォルトのサブパーサーを追加することができます。これを使用して、ユーザーによってサブパラーセルが選択されていない場合(コードでマークされた異なる行)を使用してケースを処理できます。
def set_default_subparser(self, name, args=None, positional_args=0):
"""default subparser selection. Call after setup, just before parse_args()
name: is the name of the subparser to call by default
args: if set is the argument list handed to parse_args()
, tested with 2.7, 3.2, 3.3, 3.4
it works with 2.6 assuming argparse is installed
"""
subparser_found = False
existing_default = False # check if default parser previously defined
for arg in sys.argv[1:]:
if arg in ['-h', '--help']: # global help if no subparser
break
else:
for x in self._subparsers._actions:
if not isinstance(x, argparse._SubParsersAction):
continue
for sp_name in x._name_parser_map.keys():
if sp_name in sys.argv[1:]:
subparser_found = True
if sp_name == name: # check existance of default parser
existing_default = True
if not subparser_found:
# If the default subparser is not among the existing ones,
# create a new parser.
# As this is called just before 'parse_args', the default
# parser created here will not pollute the help output.
if not existing_default:
for x in self._subparsers._actions:
if not isinstance(x, argparse._SubParsersAction):
continue
x.add_parser(name)
break # this works OK, but should I check further?
# insert default in last position before global positional
# arguments, this implies no global options are specified after
# first positional argument
if args is None:
sys.argv.insert(len(sys.argv) - positional_args, name)
else:
args.insert(len(args) - positional_args, name)
argparse.ArgumentParser.set_default_subparser = set_default_subparser
a = argparse.ArgumentParser()
b = a.add_subparsers(dest ='cmd')
sp = b.add_parser('hi')
sp2 = b.add_parser('hai')
a.set_default_subparser('hey')
parsed_args = a.parse_args()
print(parsed_args)
「デフォルト」オプションは、ヘルプにまだ表示されません。
python test_parser.py -h
usage: test_parser.py [-h] {hi,hai} ...
positional arguments:
{hi,hai}
optional arguments:
-h, --help show this help message and exit
ただし、提供されたサブパーサーの1つを呼び出し、引数が提供されていない場合にデフォルトのサブパーサーを呼び出すことを区別し、別々に処理することが可能になりました。
$ python test_parser.py hi
Namespace(cmd='hi')
$ python test_parser.py
Namespace(cmd='hey')
これが追加のより良い方法です set_default_subparser
方法:
class DefaultSubcommandArgParse(argparse.ArgumentParser):
__default_subparser = None
def set_default_subparser(self, name):
self.__default_subparser = name
def _parse_known_args(self, arg_strings, *args, **kwargs):
in_args = set(arg_strings)
d_sp = self.__default_subparser
if d_sp is not None and not {'-h', '--help'}.intersection(in_args):
for x in self._subparsers._actions:
subparser_found = (
isinstance(x, argparse._SubParsersAction) and
in_args.intersection(x._name_parser_map.keys())
)
if subparser_found:
break
else:
# insert default in first position, this implies no
# global options without a sub_parsers specified
arg_strings = [d_sp] + arg_strings
return super(DefaultSubcommandArgParse, self)._parse_known_args(
arg_strings, *args, **kwargs
)
たぶんあなたが探しているのはです dest
の議論 add_subparsers
:
(警告:Python 3.4で動作しますが、2.7では機能しません)
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(dest='cmd')
parser_hi = subparsers.add_parser('hi')
parser.parse_args([]) # Namespace(cmd=None)
これで、値を使用できます cmd
:
if cmd in [None, 'hi']:
print('command "hi"')
何も設定されていないときに使用されるデフォルト値で引数を追加できます。
これを参照してください: http://docs.python.org/dev/library/argparse.html#default
編集:
申し訳ありませんが、私はあなたの質問をもう少し速く読みました。
Argparseを介してあなたが望むことをするための直接的な方法があるとは思いません。ただし、Sys.Argvの長さを確認でき、その長さが1(スクリプト名のみ)の場合、解析のデフォルトパラメーターを手動で渡すことができます。
import argparse
a = argparse.ArgumentParser()
b = a.add_subparsers()
b.add_parser('hi')
if len(sys.argv) == 1:
a.parse_args(['hi'])
else:
a.parse_args()
それはあなたがやりたいことをすべきだと思いますが、これを箱から出してもいいと思います。
Python 2.7では、サブクラスのエラー動作をオーバーライドできます(エラーを区別する優れた方法がないのは残念です):
import argparse
class ExceptionArgParser(argparse.ArgumentParser):
def error(self, message):
if "invalid choice" in message:
# throw exception (of your choice) to catch
raise RuntimeError(message)
else:
# restore normal behaviour
super(ExceptionArgParser, self).error(message)
parser = ExceptionArgParser()
subparsers = parser.add_subparsers(title='Modes', dest='mode')
default_parser = subparsers.add_parser('default')
default_parser.add_argument('a', nargs="+")
other_parser = subparsers.add_parser('other')
other_parser.add_argument('b', nargs="+")
try:
args = parser.parse_args()
except RuntimeError:
args = default_parser.parse_args()
# force the mode into namespace
setattr(args, 'mode', 'default')
print args
メインパーサーの特定のサブパーサーのデフォルトアクションを複製して、効果的にデフォルトにすることができます。
import argparse
p = argparse.ArgumentParser()
sp = p.add_subparsers()
a = sp.add_parser('a')
a.set_defaults(func=do_a)
b = sp.add_parser('b')
b.set_defaults(func=do_b)
p.set_defaults(func=do_b)
args = p.parse_args()
if args.func:
args.func()
else:
parser.print_help()
一緒に動作しません add_subparsers(required=True)
, 、それが理由です if args.func
そこにあります。
私の場合、サブコマンド名を明示的に提供するのが最も簡単だとわかりました parse_args()
いつ argv
空だった。
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='commands')
runParser = subparsers.add_parser('run', help='[DEFAULT ACTION]')
altParser = subparsers.add_parser('alt', help='Alternate command')
altParser.add_argument('alt_val', type=str, help='Value required for alt command.')
# Here's my shortcut: If `argv` only contains the script name,
# manually inject our "default" command.
args = parser.parse_args(['run'] if len(sys.argv) == 1 else None)
print args
実行の例:
$ ./test.py
Namespace()
$ ./test.py alt blah
Namespace(alt_val='blah')
$ ./test.py blah
usage: test.py [-h] {run,alt} ...
test.py: error: invalid choice: 'blah' (choose from 'run', 'alt')
後で参照:
...
b = a.add_subparsers(dest='cmd')
b.set_defaults(cmd='hey') # <-- this makes hey as default
b.add_parser('hi')
したがって、これら2つは同じになります:
- python main.pyねえ
- python main.py