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):
...
我的问题:
- 有没有一个图书馆可以做这样的事情?
- 如果没有,是否可以编写这样的装饰器,以及如何编写?
- 有其他/更好的方法来实现我想要的吗?
Upd:
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)
如果你问我的话,相当整洁。