У меня есть программа, которая должна иметь возможность либо проверять список идентификаторов сервера, либо выдавать команду на сервер. Это означает, что если я --test
, тогда больше ничего не потребуется. Он запускает всю гамму тестов против каждого сервера и печатает результаты.
Однако, если я НЕ --test
, тогда для этого потребуется несколько параметров, таких как --id
и --command
.
Однако я не уверен, что argparse
может обрабатывать требуемые параметры в рамках взаимоисключающих групп. Код (измененный для простоты) выглядит следующим образом. Я изменил параметры, поэтому, если вы укажете -a
, тогда вам ДОЛЖЕН быть хорошим, чтобы идти, и никаких других вариантов не нужно.
import argparse
parser = argparse.ArgumentParser()
test_or_not = parser.add_mutually_exclusive_group(required=True)
test_or_not.add_argument('-a', action='store_true')
or_not = test_or_not.add_argument_group()
target = or_not.add_mutually_exclusive_group(required=True)
target.add_argument('-b',action="store_true")
target.add_argument('-c',action="store_true")
target.add_argument('-d',action="store_true")
target.add_argument('-e',action="store_true")
group = or_not.add_mutually_exclusive_group(required=True)
group.add_argument('-f',action="store_true")
group.add_argument('-g',action="store_true")
or_not.add_argument('-i',action="store_true")
or_not.add_argument('-j',action="store_true")
or_not.add_argument('-k',action="store_true")
or_not.add_argument('-l',action="store_true")
args = parser.parse_args()
Полученная ошибка возникает из-за argparse
что argparse
по-прежнему требует индивидуальных опций, даже если они находятся во взаимоисключающей группе. Есть ли способ, с помощью которого argparse
может вместить этот набор параметров или мне нужно добавить немного программирования вне argparse
?
$ python3 ~/tmp/groups.py -a
usage: groups.py [-h] -a (-b | -c | -d | -e) (-f | -g) [-i] [-j] [-k] [-l]
groups.py: error: one of the arguments -b -c -d -e is required
Изменение: я мог бы добавить новую опцию, которая полностью работает OUTSIDE из argparse
как argparse
ниже, но я хотел бы сохранить ее структурированной внутри argparse
если это вообще возможно.
import argparse
import sys
if '--test' in sys.argv:
go_do_testing()
sys.exit(0)
parser = argparse.ArgumentParser()
<snip>
Как было предложено в комментариях, путь, если вы хотите иметь взаимоисключающие test
и run
логику, - это использовать подпарамеры. Ниже приводится иллюстрация идеи:
#!/usr/bin/env python3
"""
Script to test or run commands on given servers.
./the_script.py test # To test all servers
./the_script.py run --id 127.0.0.1 --command "echo hello world"
"""
from argparse import ArgumentParser, RawDescriptionHelpFormatter as RDHF
def test_servers(servers):
"""
Given a list of servers, let test them!
"""
for server in servers:
print('Just tested server {s}'.format(s=server))
def do_actual_work(server_id, command):
"""
Given a server ID and a command, let run the command on that server!
"""
print('Connected to server {s}'.format(s=server_id))
print('Ran command {c} successfully'.format(c=command))
if __name__ == '__main__':
parser = ArgumentParser(description=__doc__, formatter_class=RDHF)
subs = parser.add_subparsers()
subs.required = True
subs.dest = 'run or test'
test_parser = subs.add_parser('test', help='Test all servers')
test_parser.set_defaults(func=test_servers)
run_parser = subs.add_parser('run', help='Run a command on the given server')
run_parser.add_argument('-i', '--id',
help='The ID of the server to connect to and run commands',
required=True)
run_parser.add_argument('-c', '--command',
help='The command to run',
required=True)
run_parser.set_defaults(func=do_actual_work)
args = parser.parse_args()
if args.func.__name__ == 'test_servers':
all_servers = ['127.0.0.1', '127.0.0.2']
test_servers(all_servers)
else:
do_actual_work(args.id, args.command)
Скрипт устанавливает оба взаимоисключающих и требуемых подпараллельных test
и run
. Для test
подпарамера больше ничего не требуется. Однако для подпункта run
потребуются как --id
и --command
. Каждый из этих подпараметров связан с назначенной целевой функцией. Для простоты у меня был test_parser
привязанный к test_servers
; а run_parser
связан с do_actual_work
.
Кроме того, вы можете вызвать сценарий следующим образом, чтобы запустить все тесты:
./the_script.py test
Чтобы запустить определенную команду на определенном сервере, вы вызываете скрипт следующим образом:
./the_script.py run --id 127 --command "echo hello world"
Надеюсь, это окажется полезным.
test
опциюsubparser
и привязатьsubparser
к функции, которая проверяет эти серверы?