AlanK
AlanK

Reputation: 9833

Python: Access argument while ArgParsing

I'm trying to parse the arguments passed to a script and execute functionality on the fly

#!/usr/bin/python

import sys
from argparse import ArgumentParser


def method_a(sometext):
    print 'a -- {0}'.format(sometext)


def method_b(sometext):
    print 'b -- {0}'.format(sometext)


parser = ArgumentParser(description='A or B')
parser.add_argument('--sometext',
                    dest='sometext',
                    required=False,
                    default=None)

option_group = parser.add_mutually_exclusive_group(required=True)
option_group.add_argument('-a',
                          dest='cmd',
                          action='store_const',
                          const=lambda: method_user(parser.sometext))

option_group.add_argument('--list',
                          '-l',
                          dest='cmd',
                          action='store_const',
                          const=lambda: method_list(parser.sometext))

args = parser.parse_args(sys.argv[1:])
args.cmd()

This unforunately throws the exception:

Traceback (most recent call last):
  File "test.py", line 39, in <module>
    args.cmd()
  File "test.py", line 34, in <lambda>
    const=lambda: method_list(parser.sometext),
AttributeError: 'ArgumentParser' object has no attribute 'sometext'

Is it possible to access the value passed to sometext while parsing later arguments? I'd like to pass the value captured in sometext to the methods being run inside the const field for the mutually exclusive group.

As a side question: is the keyword lambda required in the above example? Or will it execute the method regardless.. I'd use the lambda in a similar example below, but again, is this even required?

switch = {0: lambda: sys.exit(),
          1: lambda: method_a('sometext'),
          2: lambda: method_b('sometext')}
index = int(raw_input('Make a selection'))
switch.get(index)()

Upvotes: 0

Views: 77

Answers (1)

JSTL
JSTL

Reputation: 868

The parser instance itself doesn't hold the parsed arguments, as it is a description of what the expected arguments are and how to parse them. The return value from calling parse_args holds them. A quick way to get what you want would be:

...
option_group.add_argument('-a',
                      dest='cmd',
                      action='store_const',
                      const=lambda args: method_user(args.sometext))

option_group.add_argument('--list',
                      '-l',
                      dest='cmd',
                      action='store_const',
                      const=lambda args: method_list(args.sometext))
args = parser.parse_args()
args.cmd(args)

Ultimately, you could write your own subclasses of the argparse module that would grant you access to the parsed arguments, but I don't recommend that approach because:

  • It's a lot of work and would require subclassing private classes, which is never a good idea.
  • It would need to take into account the ordering of the arguments, which you can't rely on, being a user input.

To answer your side question, you could refer to the function itself, without having to use a lamdba declaration, such as:

...
option_group.add_argument('-a',
                      dest='cmd',
                      action='store_const',
                      const=method_user

option_group.add_argument('--list',
                      '-l',
                      dest='cmd',
                      action='store_const',
                      const=method_list
args = parser.parse_args()
args.cmd(args.sometext)

If you need to refer to a function to be invoked with some parameters, but don't want to wrap it in a lambda, you can use the partial wrapper from the functools module.

Upvotes: 1

Related Questions