How to set the value of the Argparse argument to the value of the positional argument?

I have a python script that sends a GET request. It uses Argparse to take three arguments:

  • Address : where to send the GET request
  • Host : Host to advertise in GET request
  • Resource : which resource is being requested

An example of use could be:

$ python get.py 198.252.206.16 stackoverflow.com /questions/ask

However, in most cases only the host and resource need to be specified, since the host will decide the address:

 $ host -t a stackoverflow.com
 stackoverflow.com has address 198.252.206.16

      

... The desired use could be:

$ python get.py stackoverflow.com /questions/ask

      

How can I configure Argparse so that the default value for the Address argument is the value of the Host argument?


I was prompted to show the code that currently parses the arguments. Here he is:

import argparse

parser = argparse.ArgumentParser(description=
         'Send a GET request and obtain the HTTP response header and/or body.')

parser.add_argument("-v", "--verbose",
                    help="Turn on verbose mode.",
                    action="store_true")
parser.add_argument("-p", "--port",
                    type=int,
                    default=80,
                    help="Which port to use when sending the GET request."
parser.add_argument("address",
                    help="Where to send the GET request to.")
parser.add_argument("host",
                    help="Which Host to declare in the GET request.")   
parser.add_argument("resource",
                    help="Which resource to request.")

parser.parse_args()

      

+3


source to share


3 answers


nargs='?'

handles this situation perfectly. If there are only 2 strings, they are assigned host

and resource

, and address

get the default value ( None

). If there are 3 lines, they are assigned to all 3. If that helps, think about the behavior ?

in the template re

.

Easy to assign a value host

address

after the parser is finished. There is no point in trying to fulfill this assignment in parse_args

(since the host value is not known yet).

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("address", nargs='?')
parser.add_argument("host")
parser.add_argument("resource")
args = parser.parse_args()

if args.address is None:
    args.address = args.host
print(args)

      



and usage:

usage: get.py [-h] [address] host resource

      

c []

, which neatly denotes an optional positional argument.

+6


source


If you are trying to achieve the behavior you described using ONLY positional arguments, you can use the list argument (nargs) like this:

import argparse

parser = argparse.ArgumentParser()
parser.add_argument("args", nargs="+")
parsed = parser.parse_args()
args = parsed.args
if len(args) == 3:
    ip, host, address = args
    print ip, host, address
elif len(args) == 2:
    ip, host, address = args[0], args[0], args[1]
    print ip, host, address
else:
    print "Invalid args"

      

But not only this hackish you also lose the benefits provided by argparse (you need to manually check the arguments). I recommend using optional arguments. Perhaps like this:



import argparse

parser = argparse.ArgumentParser()
parser.add_argument("-host", required=True)
parser.add_argument("-res", required=True)
parser.add_argument("-ip", required=False)
args = parser.parse_args()

ip = args.ip if args.ip else args.host
print args.host, args.res, ip

      

And execute it like this:

python2.7 test.py -host hello -res world

      

+3


source


Here you have two sensible choices that you choose, depends on how you bind to positional arguments, not -options.

  • Add a positional argument with nargs='+'

    . After parsing the arguments, check the length of this list. If it was 3, set address, host and resource for them. If it was 2, set them to host and resource and copy the address from host. Otherwise, print a usage message and throw an exception.

  • Leave host and resource as positional arguments. Change the address to a parameter. This means that the CLI will look like this:

python get.py stackoverflow.com /questions/ask --address 198.252.206.16

You can set the default None

and then check to see if it's not there after parsing the arguments, I don't think there is a way in argparse that it will automatically default to a different positional argument.

Whichever you choose is personal preference, I like 2 better (the optional arguments should be, by definition, options) because it fits better with the tool available - if you bend argparse to behave like 1, then you will have to additionally override the parameter --help

. usage message, etc., because the autogenerated defaults would be misleading.

+1


source







All Articles