tldnr: есть ли способ для данной функции автоматически создать ArgumentParser из ее подписи?
У меня есть куча функций, которые я хотел бы открыть для командной строки. Итак, в основном модуль:
def copy(foo, bar, baz):
...
def move(from, to):
...
def unlink(parrot, nomore=True):
...
if __name__ == '__main__':
argparse stuff
который можно вызвать из командной строки следующим образом:
python commands.py move spam ham
python commands.py unlink --parrot Polly
Хотя это довольно просто реализовать, здесь задействовано много проводки:
parser = argparse.ArgumentParser(...)
subparsers = parser.add_subparsers()
...
c = subparsers.add_parser('unlink', description='Unlink a parrot')
c.add_argument('--parrot', help='parrots name', required=True)
c.add_argument('--nomore', help='this parrot is no more', action='store_true')
...
c = subparsers.add_parser('move', description='Move stuff')
...
и так далее для каждой функции. Хуже всего то, что если аргументы функции меняются (а они меняются), argparse нужно синхронизировать вручную.
Было бы намного лучше, если бы функции могли сами предоставлять argparse, чтобы основной код выглядел так:
parser = argparse.ArgumentParser(...)
subparsers = parser.add_subparsers()
copy.register(subparsers)
move.register(subparsers)
unlink.register(subparsers)
...
Я подумал о чем-то в этом духе:
@args(
description='Unlink a parrot',
parrot={'required':True, 'help':'parrots name'},
nomore={'action': 'store_true', 'help': 'this parrot is no more'}
)
def unlink(parrot, nomore=True):
...
Мои вопросы:
- есть ли библиотека, которая делает что-то подобное?
- если нет, то можно ли написать такой декоратор и как?
- есть ли другой/лучший способ реализовать то, что я хочу?
Обновление:
plac кажется решением. Вот как сделать то, что я хочу, с помощью plac:
модуль команд: cmds.py:
import plac
@plac.annotations(
foo=('the foo thing'),
bar=('the bar thing'),
fast=('do a fast copy', 'flag')
)
def copy(foo, bar, fast=False):
"""Copy some foo to bar."""
pass
@plac.annotations(
parrots=('parrots names'),
nomore=('these parrots are no more', 'flag'),
repeat=('repeat n times', 'option', 'r', int)
)
def unlink(nomore=False, repeat=1, *parrots):
"""Unlink some parrots."""
pass
#more commands...
# export commands so that plac knows about them
commands = 'copy', 'unlink'
и вот основной модуль:
import plac
import cmds
plac.call(cmds)
Довольно аккуратно, если вы спросите меня.