Question

Let's say I have a python test using argparse, with several arguments:

  • IP (default: 127.0.0.1)
  • enabled_features (default: [A, B, C])

Sometimes, I'd like to change the default enabled_features, let's say to [A,B,C,D]:

  • depending on something I need the IP to find out (so it can't really be a default value in the way argparse has default values)
  • only if the user hasn't specified the "enabled_features"... that's what I have trouble to know!

So is there an attribute in the argparse classes to know, after:

opts = parser.parse_args()

...that an argument was actually specified by the user, i.e. that one has used something like:

$ python my_test.py --enabled_features A B C

and not:

$ python my_test.py

Thanks!

Was it helpful?

Solution

opts contains all the information that argparse can give you. So you have to either test for some default value (most commonly None), or the absence of the attribute (if default=argparse.SUPPRESS).

Another approach is to specify a reasonable default, and not worry whether the user specified those, or other values, in the input. Which is more important, that the user specified the values, or the values themselves?

OTHER TIPS

Something like...

myopts = vars(opts)
if opts['enabled_features'] is None:
    #Set the default parameters as you please.

Would allow you to see if they specified the opt in the command line (assuming you've added the argument to the parser).

The parser object itself saves some useful information we can use to check out the defaults we assigned when adding the argument.

Example script parser_ex.py:

import argparse

def specified_nondefault(opts, parser, arg):
  """
  Checks whether an argument was specified to be something other than the 
  default value.

  ..Note: This doesn't actually check if the argument was specified, as it
          can be 'tricked' by the user specifying the default value.

  :param argparse.Namespace opts: Parsed arguments to check.
  :param argparse.Parser parser: The parser they were parsed with.
  :param str arg: The name of the argument in question.
  :return bool: Whether the current argument value differs from the default.
  """

  if getattr(opts, arg) == parser.get_default(arg):
    return False
  return True

parser = argparse.ArgumentParser()

parser.add_argument('enabled_features', nargs='*', default=['A', 'B', 'C', 'D'])

opts = parser.parse_args()

print specified_nondefault(opts, parser, 'enabled_features')

In which case:

>> parser_ex.py 'B' True

Because we've done something non-default. While

>> parser_ex.py 'A' 'B' 'C' 'D' False

and

>> parser_ex.py False

Since this just has default input.

Note that because we're checking against an entire list, there's some somewhat undesirable behaviour that order matters and

>> parser_ex.py 'B' 'A' 'C' True

IMO, this is a problem with lumping all the features into a single argument, but you can certainly work around it one way or another if you care.

Then, if the user has/n't specified non-defualt enabled_features, you can change them based on IP as desired.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top