(半)自动生成函数的 argparsers [英] (semi-) automatic generation of argparsers for functions

查看:21
本文介绍了(半)自动生成函数的 argparsers的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

tldnr:给定一个函数,有没有办法根据它的签名自动创建一个 ArgumentParser?

我有一堆函数想要暴露给命令行.所以基本上,一个模块:

I've got a bunch of functions that I'd like to expose to the command line. So basically, a module:

 def copy(foo, bar, baz):
    ...
 def move(from, to):
    ...
 def unlink(parrot, nomore=True):
    ...

 if __name__ == '__main__':
     argparse stuff

可以像这样从命令行调用:

which can be called from the command line like this:

 python commands.py move spam ham
 python commands.py unlink --parrot Polly

虽然这很容易实现,但涉及很多布线:

Although this is pretty straightforward to implement, there's a lot of wiring involved:

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 内容.

and so on, for each function. The worst thing, should function arguments change (and they do), the argparse stuff needs to be synchronized manually.

如果函数可以为自己提供 argparse 的东西会好得多,这样主代码就会像:

It would be much nicer if the functions could provide argparse stuff for themselves, so that the main code would be like:

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 执行我想要的操作:

plac appears to be the solution. Here's how to do what I want with plac:

命令模块:cmds.py:

commands module: 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)

如果你问我,那就很整洁了.

Quite neat if you ask me.

推荐答案

你试过 plac?

文档中的示例:

# dbcli.py
import plac
from sqlalchemy.ext.sqlsoup import SqlSoup

@plac.annotations(
    db=plac.Annotation("Connection string", type=SqlSoup),
    header=plac.Annotation("Header", 'flag', 'H'),
    sqlcmd=plac.Annotation("SQL command", 'option', 'c', str, metavar="SQL"),
    delimiter=plac.Annotation("Column separator", 'option', 'd'),
    scripts=plac.Annotation("SQL scripts"),
    )
def main(db, header, sqlcmd, delimiter="|", *scripts):
    "A script to run queries and SQL scripts on a database"
    yield 'Working on %s' % db.bind.url

    if sqlcmd:
        result = db.bind.execute(sqlcmd)
        if header: # print the header
            yield delimiter.join(result.keys())
        for row in result: # print the rows
            yield delimiter.join(map(str, row))

    for script in scripts:
        db.bind.execute(open(script).read())
        yield 'executed %s' % script

if __name__ == '__main__':
    for output in plac.call(main):
        print(output)

输出:

usage: dbcli.py [-h] [-H] [-c SQL] [-d |] db [scripts [scripts ...]]

A script to run queries and SQL scripts on a database

positional arguments:
  db                    Connection string
  scripts               SQL scripts

optional arguments:
  -h, --help            show this help message and exit
  -H, --header          Header
  -c SQL, --sqlcmd SQL  SQL command
  -d |, --delimiter |   Column separator

这篇关于(半)自动生成函数的 argparsers的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆