如何允许"交错" python argparse解析器中的选项 - 值对?

时间:2017-11-21 02:37:35

标签: python argparse

我有一个python脚本,它是C ++构建系统的一部分 - 它读取C ++文件并使用libclang来提取一些元数据,这些元数据在某处存储为json。

我们在一些非常大的文件中使用这个工具。我们希望能够将其与ccache一起使用。要做到这一点,python脚本需要"看起来像" gcc在命令行上,足够接近ccache可以把它想象成一些高度非标准的c编译器碰巧产生json而不是目标代码。 (我们已经传递了很多c-compiler标志,无论如何需要经过libclang。)

因为我们必须改变解析其参数的方式,所以我将其更改为使用argparse,因为我不知道如何使用argparse做我需要的工作。问题在于我是否有一种聪明的方式,我没有想到/不知道如何更热火地做这件事。

该工具需要从命令行解析输入文件路径和输出文件路径。输出文件路径使用-o发出信号,输入文件路径可以使用-c发出信号。 (类似于gcc的工作原理......)所有其他标志应该收集在另一个列表中,该列表将转发到libclang

示例:

./args.py foo bar -o baz -c qaz
   input: qaz
   output: baz
   parser_args: ['foo', 'bar']

./args.py foo bar -c qaz -o baz
   input: qaz
   output: baz
   parser_args: ['foo', 'bar']

皱纹是它还需要支持一种奇怪的顺序,其中-o选项出现在-c和参数-c之间。

./args.py foo bar -c -o baz qaz
   input: qaz
   output: baz
   parser_args: ['foo', 'bar']

这是我在天真(公认的C-ish)python中掀起的解析器:

#!/usr/bin/env python

import sys

def help():
    print """
    This tool takes command line arguments in a way compatible with gcc. This is
    so that it can be compatible with ccache.

    Pass with -c the path to the rtdv file.
    Pass with -o the output path to the json file.
    All other args are forwarded to libclang.


    To accomodate ccache, the following syntax is also allowed:
      -c -o output input
"""


def parse_cl_args(argv):
    input = False
    output = False
    parser_args = []

    i = 1
    while i < len(argv):
        # When we see -c, go into a mode where next parameter is the source file,
        # except that -o and its argument are allowed to appear inbetween
        if argv[i] == '-c':
            i+=1
            # Consume any -o immediately after -c
            while argv[i] == '-o':
                if output:
                    raise Exception("Too many output files specified: " + output + " , " + argv[i+1])
                output = argv[i+1]
                i+=2

            # Consume -c parameter as input file
            if input:
                raise Exception("Too many input files specified: " + input + " , " + argv[i])
            input = argv[i]
            i+=1
        elif argv[i] == '-o':
            if output:
                raise Exception("Too many output files specified: " + output + " , " + argv[i+1])
            output = argv[i+1]
            i+=2
        else:
            parser_args += [argv[i]]
            i+=1

    return (input, output, parser_args)

def main():
    if '-h' in sys.argv or '--help' in sys.argv or len(sys.argv) <= 1:
         help()
         return

    (input, output, parser_args) = parse_cl_args(sys.argv)

#    if not input:
#        sys.stderr.write('Argv: ' + str(sys.argv) + '\n')
#        raise Exception("Must use -c flag to specify input file to parse.")
#
#    if not output:
#        sys.stderr.write('Argv: ' + str(sys.argv) + '\n')
#        raise Exception("Must use -o flag to specify output path for json")

    print 'input: ', input
    print 'output: ', output
    print 'parser_args: ', parser_args

if __name__ == '__main__':
    main()

有没有一种很好的方法可以使用argparse做这样的事情?

我对argparse的尝试就是这样:

  1. -c使用subparser并为其添加-o选项
  2. 还向顶级解析器添加-o选项。尝试将-o的两个版本分配给同一个变量。
  3. 使用parse_known_args收集不匹配的parser_args
  4. 问题在于我不确定如何在此策略中为-c配置subparser。一旦我将subparser命名为-c,我就可以为其添加-o选项,但我不确定如何让它收集它应该关联的令牌与args.c。从文档中我也不清楚它将如何与parse_known_args进行交互。

    无论如何,最终结果不必与我给出的代码示例相同。例如,只有在-c-o之前出现的参数被收集为parser_args而其他参数被丢弃或其他内容时,这是可以的。

    只有真的需要以ccache将调用它的方式工作。如果argparse产生的帮助是可以理解的,那就太好了。

0 个答案:

没有答案