0

I am writing an argument parser for a program. The current parser behaves like:

Simulate Roboy in MuJoCo.

positional arguments:
  P                   Proportional Gain
  I                   Derivational Gain
  D                   Integral Gain
  simRate             Simulation Rate

optional arguments:
  -h, --help          show this help message and exit
  --renderRate Hz     Render frequency. Default: Off.
  --loggingRate Hz    Logging frequency. Default: Off.
  --plot              Plotting after Finish. Default: Off.
  --controlOnlyJoint  Fix all But the specified Joint. Default: Off.

I want an additional argument --playBag. If specified, the user must ALSO input 3 further variables, one of type path and two of type integer, like --playBag shoulder.bag 10 15.

I have tried experimenting around with a subparser which is kind of working, but not really.

The full code:

import argparse
from importlib.resources import path

parser = argparse.ArgumentParser(description='Simulate Roboy in MuJoCo.')


#playBagParser.add_argument('file', type=str, help='bagfile path')

parser.add_argument('P', type=int, help='Proportional Gain')
parser.add_argument('I', type=int, help='Derivational Gain')
parser.add_argument('D', type=int, help='Integral Gain')
parser.add_argument('simRate', type=int, help='Simulation Rate')

parser.add_argument('--renderRate', metavar='Hz', type=int, help='Render frequency. Default: Off.')
parser.add_argument('--loggingRate', metavar='Hz', type=int, help='Logging frequency. Default: Off.')
parser.add_argument('--plot', action='store_true', help='Plotting after Finish. Default: Off.')
parser.add_argument('--controlOnlyJoint', action='store_true', help='Fix all But the specified Joint. Default: Off.')

#subparser = parser.add_subparsers(dest='command')
#playBagParser = subparser.add_parser('B', help='Play Bagfile')
#playBagParser.add_argument('file', type=str, default=None, help='bagfile path')
#playBagParser.add_argument('start', type=int, help='bagfile path')
#playBagParser.add_argument('duration', type=int, help='bagfile path')

args = parser.parse_args()
wjandrea
  • 28,235
  • 9
  • 60
  • 81
  • Just a heads up, the "I" in PID stands for integral, and the "D" for derivative; you've got them switched. – ddejohn Mar 14 '22 at 00:38
  • 1
    You can simply add `nargs=3` to the definition of the option. However, a `type` will be called once per argument, rather than receive all three string values as arguments, and something like `type=(path, int, int)` won't work. A custom action (subclassing `argparse.Action`) would let you handle the arguments individually. – chepner Mar 14 '22 at 00:46
  • Related: [Argparse with two values for one argument](/q/34988908/4518341) (covers number and metavar, but not type) – wjandrea Mar 14 '22 at 00:49
  • Use `nargs=3` to get the 3 arguments, and deal with the `int` conversion after parsing. The primary purpose of `argparse` is to parse the input, identifying what the users wants. There's nothing wrong with refining the values after. – hpaulj Mar 14 '22 at 02:05

1 Answers1

0

.add_argument() can take an nargs argument that specifies how many subarguments to take.

So, you can do the following:

parser.add_argument('--playBag', nargs=3)

though you will need to manually transform the latter two arguments to integers.

BrokenBenchmark
  • 18,126
  • 7
  • 21
  • 33