Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamic arguments for Python's argparse

I have a need in Python to create a list of arguments dynamically. I've created a script to demonstrate this, named args.py, shown below:

#!/usr/bin/python
import argparse

parser = argparse.ArgumentParser()
parser.add_argument('-args_file', default = 'args.txt')

with open(parser.parse_args().args_file, 'r') as f:
    args = f.readlines()

for arg in args:
    parser.add_argument('-' + arg.strip())

dynamic_args = parser.parse_args()

print dynamic_args

I also have a text file in the same folder, named args.txt, also shown below:

arg1
arg2
arg3

As expected, running args.py with no arguments results in:

Namespace(arg1=None, arg2=None, arg3=None, args_file='args.txt')

However, what I'm having trouble with is running my script with the -h argument. I would like the help to display the arguments found in the args_file, as seen in the example below:

usage: args.py [-h] [-args_file ARGS_FILE] [-arg1 ARG1] [-arg2 ARG2]
               [-arg3 ARG3]

What I'm seeing instead is:

usage: args.py [-h] [-args_file ARGS_FILE]

Moreover, if I run the script interactively (i.e. python -i arg.py), and at the interactive prompt type the command "parser.print_usage()", I get the wanted response (showing the -argN arguments). Also, typing "arg.py -arg1 1" or "arg.py arg1 1" result in "unrecognized arguments".

I've tried everything I can think of, but I've been unsuccessful thus far. Do any of the Python aficionados have any suggestions?

like image 333
Mark Atkin Avatar asked Aug 14 '14 21:08

Mark Atkin


People also ask

How do you add arguments in Argparse?

To add your arguments, use parser. add_argument() . Some important parameters to note for this method are name , type , and required . The name is exactly what it sounds like — the name of the command line field.

How do I make Argparse argument optional in Python?

Python argparse optional argument The example adds one argument having two options: a short -o and a long --ouput . These are optional arguments. The module is imported. An argument is added with add_argument .

What is action Store_true in Argparse?

The store_true option automatically creates a default value of False. Likewise, store_false will default to True when the command-line argument is not present. The source for this behavior is succinct and clear: http://hg.python.org/cpython/file/2.7/Lib/argparse.py#l861.


2 Answers

From Hazen's answer, using parents option makes it easier.

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

import argparse
argfile_parser = argparse.ArgumentParser(add_help=False)
argfile_parser.add_argument('-args_file', default = 'args.txt')
full_parser = argparse.ArgumentParser(parents=[argfile_parser])
with open(argfile_parser.parse_known_args()[0].args_file, 'r') as f:
    for arg in f:
        full_parser.add_argument('-' + arg.strip())

dynamic_args = full_parser.parse_args()

print dynamic_args
like image 105
gecko655 Avatar answered Oct 19 '22 23:10

gecko655


As Martjin pointed out, you can omit the help from the parser the first time. The other thing to do is to use parse_known_args the first time, so you only parse the args_file.

In cases like this, I like to keep things clear by using a throwaway parser for the first parse, and a full parser for the final parse:

import argparse
argfile_parser = argparse.ArgumentParser(add_help=False)
full_parser = argparse.ArgumentParser()
argfile_parser.add_argument('-args_file', default = 'args.txt')
full_parser.add_argument('-args_file', default = 'args.txt')
with open(argfile_parser.parse_known_args()[0].args_file, 'r') as f:
    for arg in f:
        full_parser.add_argument('-' + arg.strip())

dynamic_args = full_parser.parse_args()

print dynamic_args

For testing, I added a file args2.txt:

argA
argB
argC

And I think the result is what you're looking for:

lap:~$ python tmp.py -h
usage: tmp.py [-h] [-args_file ARGS_FILE] [-arg1 ARG1] [-arg2 ARG2]
              [-arg3 ARG3]

optional arguments:
  -h, --help            show this help message and exit
  -args_file ARGS_FILE
  -arg1 ARG1
  -arg2 ARG2
  -arg3 ARG3
lap:~$ python tmp.py -args_file args2.txt
Namespace(argA=None, argB=None, argC=None, args_file='args2.txt')
lap:~$ python tmp.py -h -args_file args2.txt
usage: tmp.py [-h] [-args_file ARGS_FILE] [-argA ARGA] [-argB ARGB]
              [-argC ARGC]

optional arguments:
  -h, --help            show this help message and exit
  -args_file ARGS_FILE
  -argA ARGA
  -argB ARGB
  -argC ARGC
lap:~$ python tmp.py -arg1 foo
Namespace(arg1='foo', arg2=None, arg3=None, args_file='args.txt')
lap:~$ python tmp.py -args_file args2.txt -argA bar
Namespace(argA='bar', argB=None, argC=None, args_file='args2.txt')
like image 33
John Hazen Avatar answered Oct 19 '22 23:10

John Hazen