argparse: обязательный выбор между 1 аргументом или группой аргументов - PullRequest
0 голосов
/ 28 ноября 2018

В моем приложении на python мои пользователи могут выбирать между:

  • одной датой
  • диапазоном дат (начало, конец)

Я создал вложенный argument_group внутри mutually_exclusive_group:

argument_group
+--- mutually_exclusive_group
     +--- date                 (argument)
     +--- argument_group
          +--- start           (argument)
          +--- end             (argument)

Я хочу указать своим пользователям, что либо date или группа (start, end) обязательна, и что , если они выбирают группу, требуются оба (start, end):

Это то, что я до сих пор:

ap = argparse.ArgumentParser()
grp = ap.add_argument_group('test dates')
date_group = grp.add_mutually_exclusive_group(required=True)

date_group.add_argument('--date', help='date (YYYYMMDD)')
date_range = date_group.add_argument_group('date range')

date_range.add_argument('--start',help='start date (YYYYMMDD)', required=True)
date_range.add_argument('--end',  help='end date (YYYYMMDD)', required=True)

Проблема 1:

Задание (start, end) не работает, так как argparse (я думаю) не может увидеть, что я указал argument_group частьmutually_exclusive_group вместо date, и так как mutually_exclusive_group требуется , это barfs:

$ ./app.py --start 20180101 --end 20180102
usage: app.py [-h] --date date --start date --end date
app.py: error: one of the arguments --date is required

Я могу обойти эту проблему, сделав взаимно_exclusive_group не обязательным , но это, очевидно, неверно, и не уловит случай, когда ничто не указано (поскольку равно , фактически требуется)

Проблема 2:

К сожалению, помощь по вышесказанному не отражает мое намерение:

Не существует (option_1 | option_2) вокруг параметров в mutually_exclusive_group, которые были бы, если бы я этого не сделалне может быть вложенной группы.

Кроме того, справка для start и end даже не отображается.

$ ./app.py --help
usage: app.py [-h] --date date --start date --end date

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

test dates:
  --date date        date (YYYYMMDD) (default: None)

Мне бы хотелось получить что-то вроде:

$ ./app.py --help
usage: app.py [-h] (--date date | --start date --end date)

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

test dates:
  --date date        date (YYYYMMDD) (default: None)
  --start date       start date (YYYYMMDD) (default: None)
  --end date         end date (YYYYMMDD) (default: None)

Как я могу выразить обязательный выбор между аргументом и группой аргументов?

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018

Учитывая ваш комментарий о том, что start == end, если дано --date, я бы все упростил и придерживался только двух аргументов:

class DefaultEnd(argparse.Action):
  def __call__(self, parser, namespace, values, option_string=None):
    setattr(namespace, self.dest, values)
    setattr(namespace, 'end', values)

ap = argparse.ArgumentParser()
ap.add_argument('--start', help='date (YYYYMMDD) Mandatory', action=DefaultEnd, required=True)
ap.add_argument('--end', help='date (YYYYMMDD) Optional, defaulted to START if not provided')

Используя пользовательский argparse.Action, он также по умолчанию *От 1007 * до --start, если было предоставлено только последнее:

optional arguments:
  -h, --help     show this help message and exit
  --start START  date (YYYYMMDD) Mandatory
  --end END      date (YYYYMMDD) Optional, defaulted to START if not provided

Так, если были заданы параметры:

args = ap.parse_args(['--start','20100102', '--end', '20121123'])
# args.start = 20100102
# args.end   = 20121123

Если нет:

args = ap.parse_args(['--start','20100102'])

# args.start = 20100102
# args.end   = 20100102

Конечно, вы также можете упростить ситуацию, если вы просто манипулируете args после синтаксического анализа и вообще пропускаете пользовательский argparse.Action:

ap.add_argument('--end', help='date (YYYYMMDD) Optional, defaulted to START if not provided', default=None)

...

args.end = args.end if args.end else args.start

Конечно, это может изменить способ обработки ваших кодов post-argsпоэтому эти решения могут не подходить для вас, если ваш код должен требовать args.date.

0 голосов
/ 28 ноября 2018

Я не знаю, как вы можете выразить выбор между аргументом и группой аргументов, но простым решением вашей проблемы было бы использовать следующее:

ap = argparse.ArgumentParser()
grp = ap.add_argument_group('test dates')
date_group = grp.add_mutually_exclusive_group(required=True)

date_group.add_argument('--date', help='date (YYYYMMDD)')
date_range = date_group.add_argument('--date-range',
    nargs=2, help='Start and End')

Просто укажите диапазон даткак один аргумент с двумя параметрами.

...