关于命令行:如何从python 3中的现有程序创建argparse子排序器?

How to create subparser with argparse from existing program in Python 3?

原始职位:

如果有一个可执行文件mini_program.py使用argparse具有以下结构:

1
2
3
4
5
6
7
8
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-X', '--attribute_matrix', type=str, help = 'Input: Path/to/Tab-separated-value.tsv')
    parser.add_argument('-y', '--target_vector', type=str, help = 'Input: Path/to/Tab-separated-value.tsv')
    opts = parser.parse_args()

if __name__ =="__main__":
    main()

如何创建一个使用argparse的控制器程序parent_program.py(我想是用subparser创建的?)与下面的用法类似:

1
2
3
python parent_program.py --help

blah-blah list of programs that can be used

然后使用子程序:

1
2
3
4
5
python parent_program.py mini_program --help

-X description
-y description
etc...

所有参数如何从mini_program.py向上传播到parent_program.py

编辑(更具体的错误消息):程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import argparse
def main():
    parser = argparse.ArgumentParser()
    # Subprograms
    subprograms = parser.add_subparsers(title="subprograms")
    # ============
    # mini-program
    # ============
    parser_miniprogram = subprograms.add_parser("miniprogram")

    # Input
    parser_miniprogram.add_argument('-X', '--attribute_matrix', type=str, help = 'Input: Path/to/Tab-separated-value.tsv')
    parser_miniprogram.add_argument('-y', '--target_vector', type=str, help = 'Input: Path/to/Tab-separated-value.tsv')
    opts = parser.parse_args()
    opts_miniprogram = parser_miniprogram.parse_args()
    print(opts_miniprogram.__dict__)

if __name__ =="__main__":
    main()

检查以确保文档正常工作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# parent program
python parent_program.py --help
usage: parent_program.py [-h] {miniprogram} ...

optional arguments:
  -h, --help     show this help message and exit

subprograms:
  {miniprogram}

# miniprogram
python parent_program.py miniprogram --help
usage: parent_program.py miniprogram [-h] [-X ATTRIBUTE_MATRIX]
                                     [-y TARGET_VECTOR]

optional arguments:
  -h, --help            show this help message and exit
  -X ATTRIBUTE_MATRIX, --attribute_matrix ATTRIBUTE_MATRIX
                        Input: Path/to/Tab-separated-value.tsv
  -y TARGET_VECTOR, --target_vector TARGET_VECTOR
                        Input: Path/to/Tab-separated-value.tsv

尝试运行它:

1
2
3
4
python parent_program.py miniprogram -X ../../Data/X_iris.noise_100.tsv.gz -y ../../Data/y_iris.tsv
usage: parent_program.py miniprogram [-h] [-X ATTRIBUTE_MATRIX]
                                     [-y TARGET_VECTOR]
parent_program.py miniprogram: error: unrecognized arguments: miniprogram


我的实际解决方案是对上述内容进行改编:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Controller
def main(argv=None):
    parser = argparse.ArgumentParser(prog="parent_program", add_help=True)
    parser.add_argument("subprogram")
    opts = parser.parse_args(argv)
    return opts.subprogram


# Initialize
if __name__ =="__main__":
    # Get the subprogram
    subprogram = main([sys.argv[1]])
    module = importlib.import_module(subprogram)
    module.main(sys.argv[2:])

父程序可以具有类似

1
2
3
4
5
6
import mini_program
import sys
<do its own parsing>
if 'use_mini':
    <modify sys.argv>
    mini_program.main()

如前所述,导入mini_program不会运行其分析器。但是调用它的main会,但是使用它在sys.argv中找到的列表。

父解析器应该以这样的方式编写:它接受它所需要的参数,并且不会阻塞mini想要的、-x和-y输入。然后,它将这些"额外"值放入修改过的sys.argv中,mini解析器可以处理这些值。

parse_known_args是接受未知论点的一种方式,https://docs.python.org/3/library/argparse.html部分解析

nargs=argparse.REMAINDER,https://docs.python.org/3/library/argparse.html_nargs,是收集剩余参数以供传递的另一种方法。

如果minimain写为:

1
2
3
4
5
def main(argv=None):
    parser = argparse.ArgumentParser()
    parser.add_argument('-X', '--attribute_matrix', type=str, help = 'Input: Path/to/Tab-separated-value.tsv')
    parser.add_argument('-y', '--target_vector', type=str, help = 'Input: Path/to/Tab-separated-value.tsv')
    opts = parser.parse_args(argv)

它可以用

1
mini_program.main(['-X', 'astring','-y','another'])

也就是说,使用一个明确的argv列表,而不是通过sys.argv工作。

让主解析器不响应"-h"帮助可能很棘手。subparsers可能是最干净的方法。

您可以将子部分与调用minimain结合起来。我现在不想去想那些细节。

定义main的另一种方法是:

1
2
3
4
5
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('-X', '--attribute_matrix', type=str, help = 'Input: Path/to/Tab-separated-value.tsv')
    parser.add_argument('-y', '--target_vector', type=str, help = 'Input: Path/to/Tab-separated-value.tsv')
    return parser

并用它作为

1
2
 opts = main().parse_args()
 opts = mini_program.main().parse_args()

换句话说,使用main来定义解析器,但是会延迟解析。