I have a function inside a module that creates an argparse
:
def get_options(prog_version=\'1.0\', prog_usage=\'\', misc_opts=None):
options
I prefer explicitly passing arguments instead of relying on globally available attributes such as sys.argv
(which parser.parse_args()
does internally). Thus I usually use argparse
by passing the list of arguments myself (to main()
and subsequently get_options()
and wherever you need them):
def get_options(args, prog_version='1.0', prog_usage='', misc_opts=None):
# ...
return parser.parse_args(args)
and then pass in the arguments
def main(args):
get_options(args)
if __name__ == "__main__":
main(sys.argv[1:])
that way I can replace and test any list of arguments I like
options = get_options(['-c','config.yaml'])
self.assertEquals('config.yaml', options.config)
Your error message stack is hard to read because it is in quoted form rather than code. But I think the -v
argument is producing a sys.exit
. version
is like help
- it's supposed to display a message and then exit. The -v
is used by unittest
, but is also read by your parser.
There is an argparse
unittest module, test/test_argparse.py
. You may need a development Python installation to see that. Some tests are straightforward, others use specialized testing structure. Some of that special code creates arguments in the same way you do with options
.
The are two special issues:
generating the input. parse_args
uses sys.argv[1:]
unless its argv
parameter is not None
. So you can test a parser by either modifying the sys.argv
list (unittest
has already used your commandline values), or by passing a argv=None
keyword argument into your function and on to parse_args
. Trying to make a commandline meant for the unittest
code to work with get_options
is too complicated.
trapping the output, especially the sys.exit
generated by errors. One option is to subclass ArgumentParser
and give it a different error
and/or exit
method. Another is to wrap the function call in a try
block.
unittest
takes -c
argument, but with a different syntax and meaning
-c, --catch Catch control-C and display results
and -v
is verbose
, not version
.
=============
This tests the config
argument (in a self contained one file form)
import unittest
import sys
#from mymodule import get_options
def get_options(argv=None, prog_version='1.0', prog_usage='', misc_opts=None):
# argv is optional test list; uses sys.argv[1:] is not provided
from argparse import ArgumentParser
options = [] if misc_opts is None else misc_opts
parser = ArgumentParser(usage=prog_usage) if prog_usage else ArgumentParser()
parser.add_argument('-v', '--version', action='version', version='%(prog)s {}'.format(prog_version))
parser.add_argument('-c', '--config', dest='config', help='the path to the configuration file')
for option in options:
if 'option' in option and 'destination' in option:
parser.add_argument(option['option'],
dest=option.get('destination', ''),
default=option.get('default', ''),
help=option.get('description', ''),
action=option.get('action', 'store'))
args = parser.parse_args(argv)
print('args',args)
return args
class argParseTestCase(unittest.TestCase):
def test_config(self):
sys.argv[1:]=['-c','config.yaml']
options = get_options()
self.assertEquals('config.yaml', options.config)
def test_version(self):
sys.argv[1:]=['-v']
with self.assertRaises(SystemExit):
get_options()
# testing version message requires redirecting stdout
# similarly for a misc_opts test
if __name__=='__main__':
unittest.main()