10

Using argparse in relation to Python dependencies between groups using argparse, I have an argument part of some parser group of a parser - for example:

group_simulate.add_argument('-P',
                            help='simulate FC port down',
                            nargs=1,
                            metavar='fc_port_name',
                            dest='simulate')

How it's possible to use the choices to limit the choices to a list of parameters of the next structure:

1:m:"number between 1 and 10":p:"number between 1 and 4"

I have tried to use the range option but I couldn't find a way to create a list of choices that are acceptable

examples: legal parameters:

test.py -P 1:m:4:p:2

not legal parameters:

test.py -P 1:p:2
test.py -P abvds

Thank you very much for the help guys!

Community
  • 1
  • 1
Elia
  • 193
  • 1
  • 3
  • 11

2 Answers2

21

You can define a custom type that will raise an argparse.ArgumentTypeError if the string doesn't match the format you need.

def SpecialString(v):
    fields = v.split(":")
    # Raise a value error for any part of the string
    # that doesn't match your specification. Make as many
    # checks as you need. I've only included a couple here
    # as examples.
    if len(fields) != 5:
        raise argparse.ArgumentTypeError("String must have 5 fields")
    elif not (1 <= int(fields[2]) <= 10):
        raise argparse.ArgumentTypeError("Field 3 must be between 1 and 10, inclusive")
    else:
        # If all the checks pass, just return the string as is
        return v

group_simulate.add_argument('-P',
                        type=SpecialString,
                        help='simulate FC port down',
                        nargs=1,
                        metavar='fc_port_name',
                        dest='simulate')

UPDATE: here's a full custom type to check the value. All checking is done in the regular expression, although it only gives one generic error message if any part is wrong.

def SpecialString(v):
    import re  # Unless you've already imported re previously
    try:
        return re.match("^1:m:([1-9]|10):p:(1|2|3|4)$", v).group(0)
    except:
        raise argparse.ArgumentTypeError("String '%s' does not match required format"%(v,))
mcgyver5
  • 1,153
  • 2
  • 15
  • 29
chepner
  • 497,756
  • 71
  • 530
  • 681
  • ok, thank you very much chepner for your comment, I actually was looking looking for some like regex "trick" to check the value of argument, but defining an action is a solution as well, – Elia Feb 06 '13 at 17:38
  • You can use a regex to do most of the checking; see my forthcoming update. – chepner Feb 06 '13 at 17:43
  • Thank you for the update @chepner that is an excellent example of using regex in an additional method that will check the legality. – Elia Feb 08 '13 at 08:50
  • Thanks. A small fix in the first example: if len(v) != 5: should be if len(fields) != 5: – vhardion Apr 22 '14 at 21:03
  • 1
    you could replace `(1|2|3|4)` in your regex with `[1-4]` which is more concise – Ulysse BN Feb 14 '17 at 20:19
0

If I understand the question correctly, you're simply looking for:

group_simulate.add_argument('-P',
                            help='simulate FC port down',
                            type=int, 
                            metavar='fc_port_name',
                            dest='simulate',
                            choices=range(1, 10)) # answer

Source: https://docs.python.org/3/library/argparse.html#choices

young_souvlaki
  • 1,886
  • 4
  • 24
  • 28