Argparse Exception

I have the following code to read the arguments from a file and process them using argparse, but I am getting an error, why is this?

import argparse
from ConfigParser import ConfigParser
import shlex

parser = argparse.ArgumentParser(description='Short sample app',
                                 fromfile_prefix_chars='@')

parser.add_argument('--abool', action="store_true", default=False)
parser.add_argument('--bunit', action="store", dest="bunit",type=int)
parser.add_argument('--cpath', action="store", dest="c", type=str)

print parser.parse_args(['@argparse_fromfile_prefix_chars.txt']) #name of the file is argparse_fromfile_prefix_chars.txt

      

Mistake:

usage: -c [-h] [--abool] [--bunit BUNIT] [--cpath C]
-c: error: unrecognized arguments: --bunit 289 --cpath /path/to/file.txt
To exit: use 'exit', 'quit', or Ctrl-D.

      

Argparse_fromfile_prefix_chars.txt file content

--abool
--bunit 289
--cpath /path/to/file.txt

      

+3


source to share


2 answers


argparse

expects file arguments to be one per line. The value of the entire string is one argument. So your current args file is interpreted as

python a.py '--abool' '--bunit 289' '--cpath /path/to/file.txt'

      



which is causing the error. Instead, your args file should look like this:

--abool
--bunit
289
--cpath
/path/to/file.txt

      

+1


source


The documentation for fromfile_prefix_chars

states:

Arguments read from a file should by default be one per line (but see also convert_arg_line_to_args()

) and are treated as if they were in the same location as the original argument referencing the command line file.

Note that one argument does not mean one parameter followed by all of its arguments. This stands for command line argument. Currently, all strings are interpreted as if they were the only argument.

In other words, your file should look like this:

--abool
--bunit
289
--cpath
/path/to/file.txt

      

Alternatively, you can override the method convert_arg_line_to_args()

to parse the file in a different way. There is already an implementation in the documentation that parses space-separated arguments instead of line-separated arguments:

def convert_arg_line_to_args(self, arg_line):
    # consider using shlex.split() instead of arg_line.split()
    for arg in arg_line.split():
        if not arg.strip():
            continue
        yield arg

      

I believe you can either subclass ArgumentParser

, override this method, or perhaps even set an attribute on an instance ArgumentParser

.


For some reason convert_arg_line_to_args

, the default implementation doesn't work as expected:

$echo '--abool           
--bunit
289
--cpath
/here/is/a/path
' > file.txt
$cat test_argparse.py 
import argparse

parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
parser.add_argument('--abool', action='store_true')
parser.add_argument('--bunit', type=int)
parser.add_argument('--cpath')


print(parser.parse_args(['@file.txt']))
$python test_argparse.py 
usage: test_argparse.py [-h] [--abool] [--bunit BUNIT] [--cpath CPATH]
test_argparse.py: error: unrecognized arguments:

      



However, if you use the implementation above, it works:

$cat test_argparse.py    
import argparse

def convert_arg_line_to_args(arg_line):
    for arg in arg_line.split():
        if not arg.strip():
            continue
        yield arg.strip()

parser = argparse.ArgumentParser(fromfile_prefix_chars='@')
parser.add_argument('--abool', action='store_true')
parser.add_argument('--bunit', type=int)
parser.add_argument('--cpath')
parser.convert_arg_line_to_args = convert_arg_line_to_args

print(parser.parse_args(['@file.txt']))
$python test_argparse.py 
Namespace(abool=True, bunit=289, cpath='/here/is/a/path')

      

Another workaround is to use the syntax --option=argument

:

--abool
--bunit=289
--cpath=/the/path/to/file.txt

      

However, this will not work if the parameter has more than one argument. In this case, you need to use a different implementation convert_arg_line_to_args

.


Trying to debug seems to convert_line_arg_to_args

get called with an empty string that is appended to the arguments, and the empty string is considered an argument (which is undefined).

The problem is that there are two newlines at the end of the file. In fact, if you create a file without that double line at the end, it works:

$echo -n '--abool
--bunit
289
--cpath
/here/is/a/path
' > file.txt
$python test_argparse.py 
Namespace(abool=True, bunit=289, cpath='/here/is/a/path')

      

( echo -n

does not add a newline at the end of the output).

+1


source







All Articles