Как создать подпарсер с argparse из существующей программы в Python 3? - PullRequest
0 голосов
/ 30 августа 2018

Оригинальный пост:

Если имеется исполняемый файл mini_program.py, который использует argparse со следующей структурой:

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()

Как можно создать программу контроллера parent_program.py, которая использует argparse (я думаю, с subparser?) Для использования, аналогичного приведенному ниже:

python parent_program.py --help

blah-blah list of programs that can be used

затем с использованием подпрограммы:

python parent_program.py mini_program --help

-X description
-y description
etc...

Как все параметры могут распространяться от mini_program.py до parent_program.py?

РЕДАКТИРОВАТЬ (более конкретно с сообщением об ошибке):

Программа

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()

Проверка работоспособности документов

# 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

Попытка запустить его:

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

Ответы [ 2 ]

0 голосов
/ 31 августа 2018

Мое реальное решение было адаптацией к вышесказанному:

# 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:])
0 голосов
/ 30 августа 2018

Родительская программа может иметь код типа

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#partial-parsing

nargs=argparse.REMAINDER, https://docs.python.org/3/library/argparse.html#nargs, - это еще один способ сбора оставшихся аргументов для передачи.

Если mini main было записано как:

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)

это можно вызвать с

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

, то есть с явным списком argv вместо работы с sys.argv.

Не дать основному парсеру ответить на подсказку -h может быть сложно. subparsers, вероятно, самый чистый способ сделать это.

Вы можете комбинировать подпарсеры с вызовом mini main. Я не буду пытаться выяснить эти детали сейчас.

Другой способ определить main:

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

И используйте его как

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

другими словами, используйте main, чтобы определить синтаксический анализатор, но задержите синтаксический анализ.

...