Search code examples
pythonpython-2.7runtime-errorargparse

python argparse subparser assign value to variable


i want to assign the subparser values to a variable like 'rport' so when the user call argument with value like

python example.py -sock connectmode -rport 10000 

the rport variable take the 10000 int value but that code return error in the last line in 'rport = '

AttributeError: 'Namespace' object has no attribute 'rport'

notes : the subparsers is for a function is called 'socketfunc' i wanted them to be a subargs for '-sock' argument when i execute : 'python example.py -sock connectmode -h return the secondary_parser args [!]another note : the rport and rhost variables is global to make their values available to all functions

any help ! and thanks.

the code is :

import argparse
import socket
parser = argparse.ArgumentParser(epilog='\tExample: \r\npython ' + sys.argv[0])
parser.error = parser_error
parser._optionals.title = "OPTIONS"
subparsers = parser.add_subparsers(help='Specify secondary options')
global rport , rhost
secondary_parser = subparsers.add_parser('connectmode', help='sock argument connectmode')
listenmode_parser = subparsers.add_parser('listenmode',help='sock argument listenmode')
parser.add_argument('-sock','--socket',help="tcp socket functions [!] support only ipv4 for now",action="store_true")
secondary_parser.add_argument('-rport','--remoteport',help="destination port to connect to",required=True,action='store')
secondary_parser.add_argument("-rhost",'--destination',help="destination host ip addr",required=True,action='store')
secondary_parser.set_defaults(func=socketfunc)
listenmode_parser.set_defaults(func=socketfunc)
args = parser.parse_args()
rport = args.rport

Solution

  • It's hard to figure out what you want. The description is poorly formated and rambling. But I'll try to explain what your code is doing.

    Simplified a bit:

    import argparse
    
    parser = argparse.ArgumentParser()
    parser._optionals.title = "OPTIONS"
    subparsers = parser.add_subparsers(help='Specify secondary options')
    global rport , rhost
    secondary_parser = subparsers.add_parser('connectmode', help='sock argument connectmode')
    listenmode_parser = subparsers.add_parser('listenmode',help='sock argument listenmode')
    parser.add_argument('-sock','--socket',action="store_true")
    secondary_parser.add_argument('-rport','--remoteport',required=True)
    secondary_parser.add_argument("-rhost",'--destination',required=True)
    secondary_parser.set_defaults(func='secondary')
    listenmode_parser.set_defaults(func='listen')
    args = parser.parse_args()
    print(args)
    

    With the connectmode values:

    1027:~/mypy$ python3 stack48264081.py  -sock connectmode -rport 10000 
    usage: stack48264081.py connectmode [-h] -rport REMOTEPORT -rhost DESTINATION
    stack48264081.py connectmode: error: the following arguments are required: -rhost/--destination
    

    Why? Because you defined -rhost as a required argument for the connectmode subparser. If I provide both:

    1031:~/mypy$ python3 stack48264081.py  -sock connectmode -rport 10000 -rhost foo
    Namespace(destination='foo', func='secondary', remoteport='10000', socket=True)
    

    In this case args.remoteport would work. args.rport would not, because the dest is taken from the long name, --, not the short one.

    1034:~/mypy$ python3 stack48264081.py  listenmode
    Namespace(func='listen', socket=False)
    

    args.remoteport would not work here because that argument is not defined for this subparser.

    -sock is a simple True/False argument, and has nothing to do with the subparsers.