blob: 9d68f40571fe6f6bde9a88f61b58b2c9388ab576 [file] [log] [blame]
Steven Bethardcd4ec0e2010-03-24 23:07:31 +00001# Author: Steven J. Bethard <steven.bethard@gmail.com>.
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002
3import codecs
Steven Bethard72c55382010-11-01 15:23:12 +00004import inspect
Benjamin Peterson698a18a2010-03-02 22:34:37 +00005import os
6import shutil
Steven Bethardb0270112011-01-24 21:02:50 +00007import stat
Benjamin Peterson698a18a2010-03-02 22:34:37 +00008import sys
9import textwrap
10import tempfile
11import unittest
Benjamin Peterson698a18a2010-03-02 22:34:37 +000012import argparse
13
Benjamin Peterson16f2fd02010-03-02 23:09:38 +000014from io import StringIO
15
Benjamin Peterson698a18a2010-03-02 22:34:37 +000016from test import support
Petri Lehtinen74d6c252012-12-15 22:39:32 +020017from unittest import mock
Benjamin Petersonb48af542010-04-11 20:43:16 +000018class StdIOBuffer(StringIO):
19 pass
Benjamin Peterson698a18a2010-03-02 22:34:37 +000020
Benjamin Peterson698a18a2010-03-02 22:34:37 +000021class TestCase(unittest.TestCase):
22
Steven Bethard1f1c2472010-11-01 13:56:09 +000023 def setUp(self):
24 # The tests assume that line wrapping occurs at 80 columns, but this
25 # behaviour can be overridden by setting the COLUMNS environment
Berker Peksag74102c92018-07-25 18:23:44 +030026 # variable. To ensure that this width is used, set COLUMNS to 80.
Steven Bethard1f1c2472010-11-01 13:56:09 +000027 env = support.EnvironmentVarGuard()
Berker Peksag74102c92018-07-25 18:23:44 +030028 env['COLUMNS'] = '80'
Steven Bethard1f1c2472010-11-01 13:56:09 +000029 self.addCleanup(env.__exit__)
Benjamin Peterson698a18a2010-03-02 22:34:37 +000030
Benjamin Petersonb48af542010-04-11 20:43:16 +000031
Benjamin Peterson698a18a2010-03-02 22:34:37 +000032class TempDirMixin(object):
33
34 def setUp(self):
35 self.temp_dir = tempfile.mkdtemp()
36 self.old_dir = os.getcwd()
37 os.chdir(self.temp_dir)
38
39 def tearDown(self):
40 os.chdir(self.old_dir)
Benjamin Peterson511e2222014-04-04 13:55:56 -040041 for root, dirs, files in os.walk(self.temp_dir, topdown=False):
42 for name in files:
43 os.chmod(os.path.join(self.temp_dir, name), stat.S_IWRITE)
Steven Bethardb0270112011-01-24 21:02:50 +000044 shutil.rmtree(self.temp_dir, True)
Benjamin Peterson698a18a2010-03-02 22:34:37 +000045
Steven Bethardb0270112011-01-24 21:02:50 +000046 def create_readonly_file(self, filename):
47 file_path = os.path.join(self.temp_dir, filename)
48 with open(file_path, 'w') as file:
49 file.write(filename)
50 os.chmod(file_path, stat.S_IREAD)
Benjamin Peterson698a18a2010-03-02 22:34:37 +000051
52class Sig(object):
53
54 def __init__(self, *args, **kwargs):
55 self.args = args
56 self.kwargs = kwargs
57
58
59class NS(object):
60
61 def __init__(self, **kwargs):
62 self.__dict__.update(kwargs)
63
64 def __repr__(self):
65 sorted_items = sorted(self.__dict__.items())
66 kwarg_str = ', '.join(['%s=%r' % tup for tup in sorted_items])
67 return '%s(%s)' % (type(self).__name__, kwarg_str)
68
69 def __eq__(self, other):
70 return vars(self) == vars(other)
71
Benjamin Peterson698a18a2010-03-02 22:34:37 +000072
73class ArgumentParserError(Exception):
74
75 def __init__(self, message, stdout=None, stderr=None, error_code=None):
76 Exception.__init__(self, message, stdout, stderr)
77 self.message = message
78 self.stdout = stdout
79 self.stderr = stderr
80 self.error_code = error_code
81
82
83def stderr_to_parser_error(parse_args, *args, **kwargs):
84 # if this is being called recursively and stderr or stdout is already being
85 # redirected, simply call the function and let the enclosing function
86 # catch the exception
Benjamin Petersonb48af542010-04-11 20:43:16 +000087 if isinstance(sys.stderr, StdIOBuffer) or isinstance(sys.stdout, StdIOBuffer):
Benjamin Peterson698a18a2010-03-02 22:34:37 +000088 return parse_args(*args, **kwargs)
89
90 # if this is not being called recursively, redirect stderr and
91 # use it as the ArgumentParserError message
92 old_stdout = sys.stdout
93 old_stderr = sys.stderr
Benjamin Petersonb48af542010-04-11 20:43:16 +000094 sys.stdout = StdIOBuffer()
95 sys.stderr = StdIOBuffer()
Benjamin Peterson698a18a2010-03-02 22:34:37 +000096 try:
97 try:
98 result = parse_args(*args, **kwargs)
99 for key in list(vars(result)):
100 if getattr(result, key) is sys.stdout:
101 setattr(result, key, old_stdout)
102 if getattr(result, key) is sys.stderr:
103 setattr(result, key, old_stderr)
104 return result
105 except SystemExit:
106 code = sys.exc_info()[1].code
107 stdout = sys.stdout.getvalue()
108 stderr = sys.stderr.getvalue()
109 raise ArgumentParserError("SystemExit", stdout, stderr, code)
110 finally:
111 sys.stdout = old_stdout
112 sys.stderr = old_stderr
113
114
115class ErrorRaisingArgumentParser(argparse.ArgumentParser):
116
117 def parse_args(self, *args, **kwargs):
118 parse_args = super(ErrorRaisingArgumentParser, self).parse_args
119 return stderr_to_parser_error(parse_args, *args, **kwargs)
120
121 def exit(self, *args, **kwargs):
122 exit = super(ErrorRaisingArgumentParser, self).exit
123 return stderr_to_parser_error(exit, *args, **kwargs)
124
125 def error(self, *args, **kwargs):
126 error = super(ErrorRaisingArgumentParser, self).error
127 return stderr_to_parser_error(error, *args, **kwargs)
128
129
130class ParserTesterMetaclass(type):
131 """Adds parser tests using the class attributes.
132
133 Classes of this type should specify the following attributes:
134
135 argument_signatures -- a list of Sig objects which specify
136 the signatures of Argument objects to be created
137 failures -- a list of args lists that should cause the parser
138 to fail
139 successes -- a list of (initial_args, options, remaining_args) tuples
140 where initial_args specifies the string args to be parsed,
141 options is a dict that should match the vars() of the options
142 parsed out of initial_args, and remaining_args should be any
143 remaining unparsed arguments
144 """
145
146 def __init__(cls, name, bases, bodydict):
147 if name == 'ParserTestCase':
148 return
149
150 # default parser signature is empty
151 if not hasattr(cls, 'parser_signature'):
152 cls.parser_signature = Sig()
153 if not hasattr(cls, 'parser_class'):
154 cls.parser_class = ErrorRaisingArgumentParser
155
156 # ---------------------------------------
157 # functions for adding optional arguments
158 # ---------------------------------------
159 def no_groups(parser, argument_signatures):
160 """Add all arguments directly to the parser"""
161 for sig in argument_signatures:
162 parser.add_argument(*sig.args, **sig.kwargs)
163
164 def one_group(parser, argument_signatures):
165 """Add all arguments under a single group in the parser"""
166 group = parser.add_argument_group('foo')
167 for sig in argument_signatures:
168 group.add_argument(*sig.args, **sig.kwargs)
169
170 def many_groups(parser, argument_signatures):
171 """Add each argument in its own group to the parser"""
172 for i, sig in enumerate(argument_signatures):
173 group = parser.add_argument_group('foo:%i' % i)
174 group.add_argument(*sig.args, **sig.kwargs)
175
176 # --------------------------
177 # functions for parsing args
178 # --------------------------
179 def listargs(parser, args):
180 """Parse the args by passing in a list"""
181 return parser.parse_args(args)
182
183 def sysargs(parser, args):
184 """Parse the args by defaulting to sys.argv"""
185 old_sys_argv = sys.argv
186 sys.argv = [old_sys_argv[0]] + args
187 try:
188 return parser.parse_args()
189 finally:
190 sys.argv = old_sys_argv
191
192 # class that holds the combination of one optional argument
193 # addition method and one arg parsing method
194 class AddTests(object):
195
196 def __init__(self, tester_cls, add_arguments, parse_args):
197 self._add_arguments = add_arguments
198 self._parse_args = parse_args
199
200 add_arguments_name = self._add_arguments.__name__
201 parse_args_name = self._parse_args.__name__
202 for test_func in [self.test_failures, self.test_successes]:
203 func_name = test_func.__name__
204 names = func_name, add_arguments_name, parse_args_name
205 test_name = '_'.join(names)
206
207 def wrapper(self, test_func=test_func):
208 test_func(self)
209 try:
210 wrapper.__name__ = test_name
211 except TypeError:
212 pass
213 setattr(tester_cls, test_name, wrapper)
214
215 def _get_parser(self, tester):
216 args = tester.parser_signature.args
217 kwargs = tester.parser_signature.kwargs
218 parser = tester.parser_class(*args, **kwargs)
219 self._add_arguments(parser, tester.argument_signatures)
220 return parser
221
222 def test_failures(self, tester):
223 parser = self._get_parser(tester)
224 for args_str in tester.failures:
225 args = args_str.split()
Ezio Melotti12b7f482014-08-05 02:24:03 +0300226 with tester.assertRaises(ArgumentParserError, msg=args):
227 parser.parse_args(args)
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000228
229 def test_successes(self, tester):
230 parser = self._get_parser(tester)
231 for args, expected_ns in tester.successes:
232 if isinstance(args, str):
233 args = args.split()
234 result_ns = self._parse_args(parser, args)
235 tester.assertEqual(expected_ns, result_ns)
236
237 # add tests for each combination of an optionals adding method
238 # and an arg parsing method
239 for add_arguments in [no_groups, one_group, many_groups]:
240 for parse_args in [listargs, sysargs]:
241 AddTests(cls, add_arguments, parse_args)
242
243bases = TestCase,
244ParserTestCase = ParserTesterMetaclass('ParserTestCase', bases, {})
245
246# ===============
247# Optionals tests
248# ===============
249
250class TestOptionalsSingleDash(ParserTestCase):
251 """Test an Optional with a single-dash option string"""
252
253 argument_signatures = [Sig('-x')]
254 failures = ['-x', 'a', '--foo', '-x --foo', '-x -y']
255 successes = [
256 ('', NS(x=None)),
257 ('-x a', NS(x='a')),
258 ('-xa', NS(x='a')),
259 ('-x -1', NS(x='-1')),
260 ('-x-1', NS(x='-1')),
261 ]
262
263
264class TestOptionalsSingleDashCombined(ParserTestCase):
265 """Test an Optional with a single-dash option string"""
266
267 argument_signatures = [
268 Sig('-x', action='store_true'),
269 Sig('-yyy', action='store_const', const=42),
270 Sig('-z'),
271 ]
272 failures = ['a', '--foo', '-xa', '-x --foo', '-x -z', '-z -x',
273 '-yx', '-yz a', '-yyyx', '-yyyza', '-xyza']
274 successes = [
275 ('', NS(x=False, yyy=None, z=None)),
276 ('-x', NS(x=True, yyy=None, z=None)),
277 ('-za', NS(x=False, yyy=None, z='a')),
278 ('-z a', NS(x=False, yyy=None, z='a')),
279 ('-xza', NS(x=True, yyy=None, z='a')),
280 ('-xz a', NS(x=True, yyy=None, z='a')),
281 ('-x -za', NS(x=True, yyy=None, z='a')),
282 ('-x -z a', NS(x=True, yyy=None, z='a')),
283 ('-y', NS(x=False, yyy=42, z=None)),
284 ('-yyy', NS(x=False, yyy=42, z=None)),
285 ('-x -yyy -za', NS(x=True, yyy=42, z='a')),
286 ('-x -yyy -z a', NS(x=True, yyy=42, z='a')),
287 ]
288
289
290class TestOptionalsSingleDashLong(ParserTestCase):
291 """Test an Optional with a multi-character single-dash option string"""
292
293 argument_signatures = [Sig('-foo')]
294 failures = ['-foo', 'a', '--foo', '-foo --foo', '-foo -y', '-fooa']
295 successes = [
296 ('', NS(foo=None)),
297 ('-foo a', NS(foo='a')),
298 ('-foo -1', NS(foo='-1')),
299 ('-fo a', NS(foo='a')),
300 ('-f a', NS(foo='a')),
301 ]
302
303
304class TestOptionalsSingleDashSubsetAmbiguous(ParserTestCase):
305 """Test Optionals where option strings are subsets of each other"""
306
307 argument_signatures = [Sig('-f'), Sig('-foobar'), Sig('-foorab')]
308 failures = ['-f', '-foo', '-fo', '-foo b', '-foob', '-fooba', '-foora']
309 successes = [
310 ('', NS(f=None, foobar=None, foorab=None)),
311 ('-f a', NS(f='a', foobar=None, foorab=None)),
312 ('-fa', NS(f='a', foobar=None, foorab=None)),
313 ('-foa', NS(f='oa', foobar=None, foorab=None)),
314 ('-fooa', NS(f='ooa', foobar=None, foorab=None)),
315 ('-foobar a', NS(f=None, foobar='a', foorab=None)),
316 ('-foorab a', NS(f=None, foobar=None, foorab='a')),
317 ]
318
319
320class TestOptionalsSingleDashAmbiguous(ParserTestCase):
321 """Test Optionals that partially match but are not subsets"""
322
323 argument_signatures = [Sig('-foobar'), Sig('-foorab')]
324 failures = ['-f', '-f a', '-fa', '-foa', '-foo', '-fo', '-foo b']
325 successes = [
326 ('', NS(foobar=None, foorab=None)),
327 ('-foob a', NS(foobar='a', foorab=None)),
328 ('-foor a', NS(foobar=None, foorab='a')),
329 ('-fooba a', NS(foobar='a', foorab=None)),
330 ('-foora a', NS(foobar=None, foorab='a')),
331 ('-foobar a', NS(foobar='a', foorab=None)),
332 ('-foorab a', NS(foobar=None, foorab='a')),
333 ]
334
335
336class TestOptionalsNumeric(ParserTestCase):
337 """Test an Optional with a short opt string"""
338
339 argument_signatures = [Sig('-1', dest='one')]
340 failures = ['-1', 'a', '-1 --foo', '-1 -y', '-1 -1', '-1 -2']
341 successes = [
342 ('', NS(one=None)),
343 ('-1 a', NS(one='a')),
344 ('-1a', NS(one='a')),
345 ('-1-2', NS(one='-2')),
346 ]
347
348
349class TestOptionalsDoubleDash(ParserTestCase):
350 """Test an Optional with a double-dash option string"""
351
352 argument_signatures = [Sig('--foo')]
353 failures = ['--foo', '-f', '-f a', 'a', '--foo -x', '--foo --bar']
354 successes = [
355 ('', NS(foo=None)),
356 ('--foo a', NS(foo='a')),
357 ('--foo=a', NS(foo='a')),
358 ('--foo -2.5', NS(foo='-2.5')),
359 ('--foo=-2.5', NS(foo='-2.5')),
360 ]
361
362
363class TestOptionalsDoubleDashPartialMatch(ParserTestCase):
364 """Tests partial matching with a double-dash option string"""
365
366 argument_signatures = [
367 Sig('--badger', action='store_true'),
368 Sig('--bat'),
369 ]
370 failures = ['--bar', '--b', '--ba', '--b=2', '--ba=4', '--badge 5']
371 successes = [
372 ('', NS(badger=False, bat=None)),
373 ('--bat X', NS(badger=False, bat='X')),
374 ('--bad', NS(badger=True, bat=None)),
375 ('--badg', NS(badger=True, bat=None)),
376 ('--badge', NS(badger=True, bat=None)),
377 ('--badger', NS(badger=True, bat=None)),
378 ]
379
380
381class TestOptionalsDoubleDashPrefixMatch(ParserTestCase):
382 """Tests when one double-dash option string is a prefix of another"""
383
384 argument_signatures = [
385 Sig('--badger', action='store_true'),
386 Sig('--ba'),
387 ]
388 failures = ['--bar', '--b', '--ba', '--b=2', '--badge 5']
389 successes = [
390 ('', NS(badger=False, ba=None)),
391 ('--ba X', NS(badger=False, ba='X')),
392 ('--ba=X', NS(badger=False, ba='X')),
393 ('--bad', NS(badger=True, ba=None)),
394 ('--badg', NS(badger=True, ba=None)),
395 ('--badge', NS(badger=True, ba=None)),
396 ('--badger', NS(badger=True, ba=None)),
397 ]
398
399
400class TestOptionalsSingleDoubleDash(ParserTestCase):
401 """Test an Optional with single- and double-dash option strings"""
402
403 argument_signatures = [
404 Sig('-f', action='store_true'),
405 Sig('--bar'),
406 Sig('-baz', action='store_const', const=42),
407 ]
408 failures = ['--bar', '-fbar', '-fbaz', '-bazf', '-b B', 'B']
409 successes = [
410 ('', NS(f=False, bar=None, baz=None)),
411 ('-f', NS(f=True, bar=None, baz=None)),
412 ('--ba B', NS(f=False, bar='B', baz=None)),
413 ('-f --bar B', NS(f=True, bar='B', baz=None)),
414 ('-f -b', NS(f=True, bar=None, baz=42)),
415 ('-ba -f', NS(f=True, bar=None, baz=42)),
416 ]
417
418
419class TestOptionalsAlternatePrefixChars(ParserTestCase):
R. David Murray88c49fe2010-08-03 17:56:09 +0000420 """Test an Optional with option strings with custom prefixes"""
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000421
422 parser_signature = Sig(prefix_chars='+:/', add_help=False)
423 argument_signatures = [
424 Sig('+f', action='store_true'),
425 Sig('::bar'),
426 Sig('/baz', action='store_const', const=42),
427 ]
R. David Murray88c49fe2010-08-03 17:56:09 +0000428 failures = ['--bar', '-fbar', '-b B', 'B', '-f', '--bar B', '-baz', '-h', '--help', '+h', '::help', '/help']
429 successes = [
430 ('', NS(f=False, bar=None, baz=None)),
431 ('+f', NS(f=True, bar=None, baz=None)),
432 ('::ba B', NS(f=False, bar='B', baz=None)),
433 ('+f ::bar B', NS(f=True, bar='B', baz=None)),
434 ('+f /b', NS(f=True, bar=None, baz=42)),
435 ('/ba +f', NS(f=True, bar=None, baz=42)),
436 ]
437
438
439class TestOptionalsAlternatePrefixCharsAddedHelp(ParserTestCase):
440 """When ``-`` not in prefix_chars, default operators created for help
441 should use the prefix_chars in use rather than - or --
442 http://bugs.python.org/issue9444"""
443
444 parser_signature = Sig(prefix_chars='+:/', add_help=True)
445 argument_signatures = [
446 Sig('+f', action='store_true'),
447 Sig('::bar'),
448 Sig('/baz', action='store_const', const=42),
449 ]
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000450 failures = ['--bar', '-fbar', '-b B', 'B', '-f', '--bar B', '-baz']
451 successes = [
452 ('', NS(f=False, bar=None, baz=None)),
453 ('+f', NS(f=True, bar=None, baz=None)),
454 ('::ba B', NS(f=False, bar='B', baz=None)),
455 ('+f ::bar B', NS(f=True, bar='B', baz=None)),
456 ('+f /b', NS(f=True, bar=None, baz=42)),
R. David Murray88c49fe2010-08-03 17:56:09 +0000457 ('/ba +f', NS(f=True, bar=None, baz=42))
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000458 ]
459
Steven Bethard1ca45a52010-11-01 15:57:36 +0000460
461class TestOptionalsAlternatePrefixCharsMultipleShortArgs(ParserTestCase):
462 """Verify that Optionals must be called with their defined prefixes"""
463
464 parser_signature = Sig(prefix_chars='+-', add_help=False)
465 argument_signatures = [
466 Sig('-x', action='store_true'),
467 Sig('+y', action='store_true'),
468 Sig('+z', action='store_true'),
469 ]
470 failures = ['-w',
471 '-xyz',
472 '+x',
473 '-y',
474 '+xyz',
475 ]
476 successes = [
477 ('', NS(x=False, y=False, z=False)),
478 ('-x', NS(x=True, y=False, z=False)),
479 ('+y -x', NS(x=True, y=True, z=False)),
480 ('+yz -x', NS(x=True, y=True, z=True)),
481 ]
482
483
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000484class TestOptionalsShortLong(ParserTestCase):
485 """Test a combination of single- and double-dash option strings"""
486
487 argument_signatures = [
488 Sig('-v', '--verbose', '-n', '--noisy', action='store_true'),
489 ]
490 failures = ['--x --verbose', '-N', 'a', '-v x']
491 successes = [
492 ('', NS(verbose=False)),
493 ('-v', NS(verbose=True)),
494 ('--verbose', NS(verbose=True)),
495 ('-n', NS(verbose=True)),
496 ('--noisy', NS(verbose=True)),
497 ]
498
499
500class TestOptionalsDest(ParserTestCase):
501 """Tests various means of setting destination"""
502
503 argument_signatures = [Sig('--foo-bar'), Sig('--baz', dest='zabbaz')]
504 failures = ['a']
505 successes = [
506 ('--foo-bar f', NS(foo_bar='f', zabbaz=None)),
507 ('--baz g', NS(foo_bar=None, zabbaz='g')),
508 ('--foo-bar h --baz i', NS(foo_bar='h', zabbaz='i')),
509 ('--baz j --foo-bar k', NS(foo_bar='k', zabbaz='j')),
510 ]
511
512
513class TestOptionalsDefault(ParserTestCase):
514 """Tests specifying a default for an Optional"""
515
516 argument_signatures = [Sig('-x'), Sig('-y', default=42)]
517 failures = ['a']
518 successes = [
519 ('', NS(x=None, y=42)),
520 ('-xx', NS(x='x', y=42)),
521 ('-yy', NS(x=None, y='y')),
522 ]
523
524
525class TestOptionalsNargsDefault(ParserTestCase):
526 """Tests not specifying the number of args for an Optional"""
527
528 argument_signatures = [Sig('-x')]
529 failures = ['a', '-x']
530 successes = [
531 ('', NS(x=None)),
532 ('-x a', NS(x='a')),
533 ]
534
535
536class TestOptionalsNargs1(ParserTestCase):
Martin Pantercc71a792016-04-05 06:19:42 +0000537 """Tests specifying 1 arg for an Optional"""
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000538
539 argument_signatures = [Sig('-x', nargs=1)]
540 failures = ['a', '-x']
541 successes = [
542 ('', NS(x=None)),
543 ('-x a', NS(x=['a'])),
544 ]
545
546
547class TestOptionalsNargs3(ParserTestCase):
Martin Pantercc71a792016-04-05 06:19:42 +0000548 """Tests specifying 3 args for an Optional"""
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000549
550 argument_signatures = [Sig('-x', nargs=3)]
551 failures = ['a', '-x', '-x a', '-x a b', 'a -x', 'a -x b']
552 successes = [
553 ('', NS(x=None)),
554 ('-x a b c', NS(x=['a', 'b', 'c'])),
555 ]
556
557
558class TestOptionalsNargsOptional(ParserTestCase):
559 """Tests specifying an Optional arg for an Optional"""
560
561 argument_signatures = [
562 Sig('-w', nargs='?'),
563 Sig('-x', nargs='?', const=42),
564 Sig('-y', nargs='?', default='spam'),
565 Sig('-z', nargs='?', type=int, const='42', default='84'),
566 ]
567 failures = ['2']
568 successes = [
569 ('', NS(w=None, x=None, y='spam', z=84)),
570 ('-w', NS(w=None, x=None, y='spam', z=84)),
571 ('-w 2', NS(w='2', x=None, y='spam', z=84)),
572 ('-x', NS(w=None, x=42, y='spam', z=84)),
573 ('-x 2', NS(w=None, x='2', y='spam', z=84)),
574 ('-y', NS(w=None, x=None, y=None, z=84)),
575 ('-y 2', NS(w=None, x=None, y='2', z=84)),
576 ('-z', NS(w=None, x=None, y='spam', z=42)),
577 ('-z 2', NS(w=None, x=None, y='spam', z=2)),
578 ]
579
580
581class TestOptionalsNargsZeroOrMore(ParserTestCase):
Martin Pantercc71a792016-04-05 06:19:42 +0000582 """Tests specifying args for an Optional that accepts zero or more"""
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000583
584 argument_signatures = [
585 Sig('-x', nargs='*'),
586 Sig('-y', nargs='*', default='spam'),
587 ]
588 failures = ['a']
589 successes = [
590 ('', NS(x=None, y='spam')),
591 ('-x', NS(x=[], y='spam')),
592 ('-x a', NS(x=['a'], y='spam')),
593 ('-x a b', NS(x=['a', 'b'], y='spam')),
594 ('-y', NS(x=None, y=[])),
595 ('-y a', NS(x=None, y=['a'])),
596 ('-y a b', NS(x=None, y=['a', 'b'])),
597 ]
598
599
600class TestOptionalsNargsOneOrMore(ParserTestCase):
Martin Pantercc71a792016-04-05 06:19:42 +0000601 """Tests specifying args for an Optional that accepts one or more"""
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000602
603 argument_signatures = [
604 Sig('-x', nargs='+'),
605 Sig('-y', nargs='+', default='spam'),
606 ]
607 failures = ['a', '-x', '-y', 'a -x', 'a -y b']
608 successes = [
609 ('', NS(x=None, y='spam')),
610 ('-x a', NS(x=['a'], y='spam')),
611 ('-x a b', NS(x=['a', 'b'], y='spam')),
612 ('-y a', NS(x=None, y=['a'])),
613 ('-y a b', NS(x=None, y=['a', 'b'])),
614 ]
615
616
617class TestOptionalsChoices(ParserTestCase):
618 """Tests specifying the choices for an Optional"""
619
620 argument_signatures = [
621 Sig('-f', choices='abc'),
622 Sig('-g', type=int, choices=range(5))]
623 failures = ['a', '-f d', '-fad', '-ga', '-g 6']
624 successes = [
625 ('', NS(f=None, g=None)),
626 ('-f a', NS(f='a', g=None)),
627 ('-f c', NS(f='c', g=None)),
628 ('-g 0', NS(f=None, g=0)),
629 ('-g 03', NS(f=None, g=3)),
630 ('-fb -g4', NS(f='b', g=4)),
631 ]
632
633
634class TestOptionalsRequired(ParserTestCase):
Benjamin Peterson82f34ad2015-01-13 09:17:24 -0500635 """Tests an optional action that is required"""
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000636
637 argument_signatures = [
638 Sig('-x', type=int, required=True),
639 ]
640 failures = ['a', '']
641 successes = [
642 ('-x 1', NS(x=1)),
643 ('-x42', NS(x=42)),
644 ]
645
646
647class TestOptionalsActionStore(ParserTestCase):
648 """Tests the store action for an Optional"""
649
650 argument_signatures = [Sig('-x', action='store')]
651 failures = ['a', 'a -x']
652 successes = [
653 ('', NS(x=None)),
654 ('-xfoo', NS(x='foo')),
655 ]
656
657
658class TestOptionalsActionStoreConst(ParserTestCase):
659 """Tests the store_const action for an Optional"""
660
661 argument_signatures = [Sig('-y', action='store_const', const=object)]
662 failures = ['a']
663 successes = [
664 ('', NS(y=None)),
665 ('-y', NS(y=object)),
666 ]
667
668
669class TestOptionalsActionStoreFalse(ParserTestCase):
670 """Tests the store_false action for an Optional"""
671
672 argument_signatures = [Sig('-z', action='store_false')]
673 failures = ['a', '-za', '-z a']
674 successes = [
675 ('', NS(z=True)),
676 ('-z', NS(z=False)),
677 ]
678
679
680class TestOptionalsActionStoreTrue(ParserTestCase):
681 """Tests the store_true action for an Optional"""
682
683 argument_signatures = [Sig('--apple', action='store_true')]
684 failures = ['a', '--apple=b', '--apple b']
685 successes = [
686 ('', NS(apple=False)),
687 ('--apple', NS(apple=True)),
688 ]
689
690
691class TestOptionalsActionAppend(ParserTestCase):
692 """Tests the append action for an Optional"""
693
694 argument_signatures = [Sig('--baz', action='append')]
695 failures = ['a', '--baz', 'a --baz', '--baz a b']
696 successes = [
697 ('', NS(baz=None)),
698 ('--baz a', NS(baz=['a'])),
699 ('--baz a --baz b', NS(baz=['a', 'b'])),
700 ]
701
702
703class TestOptionalsActionAppendWithDefault(ParserTestCase):
704 """Tests the append action for an Optional"""
705
706 argument_signatures = [Sig('--baz', action='append', default=['X'])]
707 failures = ['a', '--baz', 'a --baz', '--baz a b']
708 successes = [
709 ('', NS(baz=['X'])),
710 ('--baz a', NS(baz=['X', 'a'])),
711 ('--baz a --baz b', NS(baz=['X', 'a', 'b'])),
712 ]
713
714
715class TestOptionalsActionAppendConst(ParserTestCase):
716 """Tests the append_const action for an Optional"""
717
718 argument_signatures = [
719 Sig('-b', action='append_const', const=Exception),
720 Sig('-c', action='append', dest='b'),
721 ]
722 failures = ['a', '-c', 'a -c', '-bx', '-b x']
723 successes = [
724 ('', NS(b=None)),
725 ('-b', NS(b=[Exception])),
726 ('-b -cx -b -cyz', NS(b=[Exception, 'x', Exception, 'yz'])),
727 ]
728
729
730class TestOptionalsActionAppendConstWithDefault(ParserTestCase):
731 """Tests the append_const action for an Optional"""
732
733 argument_signatures = [
734 Sig('-b', action='append_const', const=Exception, default=['X']),
735 Sig('-c', action='append', dest='b'),
736 ]
737 failures = ['a', '-c', 'a -c', '-bx', '-b x']
738 successes = [
739 ('', NS(b=['X'])),
740 ('-b', NS(b=['X', Exception])),
741 ('-b -cx -b -cyz', NS(b=['X', Exception, 'x', Exception, 'yz'])),
742 ]
743
744
745class TestOptionalsActionCount(ParserTestCase):
746 """Tests the count action for an Optional"""
747
748 argument_signatures = [Sig('-x', action='count')]
749 failures = ['a', '-x a', '-x b', '-x a -x b']
750 successes = [
751 ('', NS(x=None)),
752 ('-x', NS(x=1)),
753 ]
754
755
Berker Peksag8089cd62015-02-14 01:39:17 +0200756class TestOptionalsAllowLongAbbreviation(ParserTestCase):
757 """Allow long options to be abbreviated unambiguously"""
758
759 argument_signatures = [
760 Sig('--foo'),
761 Sig('--foobaz'),
762 Sig('--fooble', action='store_true'),
763 ]
764 failures = ['--foob 5', '--foob']
765 successes = [
766 ('', NS(foo=None, foobaz=None, fooble=False)),
767 ('--foo 7', NS(foo='7', foobaz=None, fooble=False)),
768 ('--fooba a', NS(foo=None, foobaz='a', fooble=False)),
769 ('--foobl --foo g', NS(foo='g', foobaz=None, fooble=True)),
770 ]
771
772
773class TestOptionalsDisallowLongAbbreviation(ParserTestCase):
774 """Do not allow abbreviations of long options at all"""
775
776 parser_signature = Sig(allow_abbrev=False)
777 argument_signatures = [
778 Sig('--foo'),
779 Sig('--foodle', action='store_true'),
780 Sig('--foonly'),
781 ]
782 failures = ['-foon 3', '--foon 3', '--food', '--food --foo 2']
783 successes = [
784 ('', NS(foo=None, foodle=False, foonly=None)),
785 ('--foo 3', NS(foo='3', foodle=False, foonly=None)),
786 ('--foonly 7 --foodle --foo 2', NS(foo='2', foodle=True, foonly='7')),
787 ]
788
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000789# ================
790# Positional tests
791# ================
792
793class TestPositionalsNargsNone(ParserTestCase):
794 """Test a Positional that doesn't specify nargs"""
795
796 argument_signatures = [Sig('foo')]
797 failures = ['', '-x', 'a b']
798 successes = [
799 ('a', NS(foo='a')),
800 ]
801
802
803class TestPositionalsNargs1(ParserTestCase):
804 """Test a Positional that specifies an nargs of 1"""
805
806 argument_signatures = [Sig('foo', nargs=1)]
807 failures = ['', '-x', 'a b']
808 successes = [
809 ('a', NS(foo=['a'])),
810 ]
811
812
813class TestPositionalsNargs2(ParserTestCase):
814 """Test a Positional that specifies an nargs of 2"""
815
816 argument_signatures = [Sig('foo', nargs=2)]
817 failures = ['', 'a', '-x', 'a b c']
818 successes = [
819 ('a b', NS(foo=['a', 'b'])),
820 ]
821
822
823class TestPositionalsNargsZeroOrMore(ParserTestCase):
824 """Test a Positional that specifies unlimited nargs"""
825
826 argument_signatures = [Sig('foo', nargs='*')]
827 failures = ['-x']
828 successes = [
829 ('', NS(foo=[])),
830 ('a', NS(foo=['a'])),
831 ('a b', NS(foo=['a', 'b'])),
832 ]
833
834
835class TestPositionalsNargsZeroOrMoreDefault(ParserTestCase):
836 """Test a Positional that specifies unlimited nargs and a default"""
837
838 argument_signatures = [Sig('foo', nargs='*', default='bar')]
839 failures = ['-x']
840 successes = [
841 ('', NS(foo='bar')),
842 ('a', NS(foo=['a'])),
843 ('a b', NS(foo=['a', 'b'])),
844 ]
845
846
847class TestPositionalsNargsOneOrMore(ParserTestCase):
848 """Test a Positional that specifies one or more nargs"""
849
850 argument_signatures = [Sig('foo', nargs='+')]
851 failures = ['', '-x']
852 successes = [
853 ('a', NS(foo=['a'])),
854 ('a b', NS(foo=['a', 'b'])),
855 ]
856
857
858class TestPositionalsNargsOptional(ParserTestCase):
859 """Tests an Optional Positional"""
860
861 argument_signatures = [Sig('foo', nargs='?')]
862 failures = ['-x', 'a b']
863 successes = [
864 ('', NS(foo=None)),
865 ('a', NS(foo='a')),
866 ]
867
868
869class TestPositionalsNargsOptionalDefault(ParserTestCase):
870 """Tests an Optional Positional with a default value"""
871
872 argument_signatures = [Sig('foo', nargs='?', default=42)]
873 failures = ['-x', 'a b']
874 successes = [
875 ('', NS(foo=42)),
876 ('a', NS(foo='a')),
877 ]
878
879
880class TestPositionalsNargsOptionalConvertedDefault(ParserTestCase):
881 """Tests an Optional Positional with a default value
882 that needs to be converted to the appropriate type.
883 """
884
885 argument_signatures = [
886 Sig('foo', nargs='?', type=int, default='42'),
887 ]
888 failures = ['-x', 'a b', '1 2']
889 successes = [
890 ('', NS(foo=42)),
891 ('1', NS(foo=1)),
892 ]
893
894
895class TestPositionalsNargsNoneNone(ParserTestCase):
896 """Test two Positionals that don't specify nargs"""
897
898 argument_signatures = [Sig('foo'), Sig('bar')]
899 failures = ['', '-x', 'a', 'a b c']
900 successes = [
901 ('a b', NS(foo='a', bar='b')),
902 ]
903
904
905class TestPositionalsNargsNone1(ParserTestCase):
906 """Test a Positional with no nargs followed by one with 1"""
907
908 argument_signatures = [Sig('foo'), Sig('bar', nargs=1)]
909 failures = ['', '--foo', 'a', 'a b c']
910 successes = [
911 ('a b', NS(foo='a', bar=['b'])),
912 ]
913
914
915class TestPositionalsNargs2None(ParserTestCase):
916 """Test a Positional with 2 nargs followed by one with none"""
917
918 argument_signatures = [Sig('foo', nargs=2), Sig('bar')]
919 failures = ['', '--foo', 'a', 'a b', 'a b c d']
920 successes = [
921 ('a b c', NS(foo=['a', 'b'], bar='c')),
922 ]
923
924
925class TestPositionalsNargsNoneZeroOrMore(ParserTestCase):
926 """Test a Positional with no nargs followed by one with unlimited"""
927
928 argument_signatures = [Sig('foo'), Sig('bar', nargs='*')]
929 failures = ['', '--foo']
930 successes = [
931 ('a', NS(foo='a', bar=[])),
932 ('a b', NS(foo='a', bar=['b'])),
933 ('a b c', NS(foo='a', bar=['b', 'c'])),
934 ]
935
936
937class TestPositionalsNargsNoneOneOrMore(ParserTestCase):
938 """Test a Positional with no nargs followed by one with one or more"""
939
940 argument_signatures = [Sig('foo'), Sig('bar', nargs='+')]
941 failures = ['', '--foo', 'a']
942 successes = [
943 ('a b', NS(foo='a', bar=['b'])),
944 ('a b c', NS(foo='a', bar=['b', 'c'])),
945 ]
946
947
948class TestPositionalsNargsNoneOptional(ParserTestCase):
949 """Test a Positional with no nargs followed by one with an Optional"""
950
951 argument_signatures = [Sig('foo'), Sig('bar', nargs='?')]
952 failures = ['', '--foo', 'a b c']
953 successes = [
954 ('a', NS(foo='a', bar=None)),
955 ('a b', NS(foo='a', bar='b')),
956 ]
957
958
959class TestPositionalsNargsZeroOrMoreNone(ParserTestCase):
960 """Test a Positional with unlimited nargs followed by one with none"""
961
962 argument_signatures = [Sig('foo', nargs='*'), Sig('bar')]
963 failures = ['', '--foo']
964 successes = [
965 ('a', NS(foo=[], bar='a')),
966 ('a b', NS(foo=['a'], bar='b')),
967 ('a b c', NS(foo=['a', 'b'], bar='c')),
968 ]
969
970
971class TestPositionalsNargsOneOrMoreNone(ParserTestCase):
972 """Test a Positional with one or more nargs followed by one with none"""
973
974 argument_signatures = [Sig('foo', nargs='+'), Sig('bar')]
975 failures = ['', '--foo', 'a']
976 successes = [
977 ('a b', NS(foo=['a'], bar='b')),
978 ('a b c', NS(foo=['a', 'b'], bar='c')),
979 ]
980
981
982class TestPositionalsNargsOptionalNone(ParserTestCase):
983 """Test a Positional with an Optional nargs followed by one with none"""
984
985 argument_signatures = [Sig('foo', nargs='?', default=42), Sig('bar')]
986 failures = ['', '--foo', 'a b c']
987 successes = [
988 ('a', NS(foo=42, bar='a')),
989 ('a b', NS(foo='a', bar='b')),
990 ]
991
992
993class TestPositionalsNargs2ZeroOrMore(ParserTestCase):
994 """Test a Positional with 2 nargs followed by one with unlimited"""
995
996 argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='*')]
997 failures = ['', '--foo', 'a']
998 successes = [
999 ('a b', NS(foo=['a', 'b'], bar=[])),
1000 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
1001 ]
1002
1003
1004class TestPositionalsNargs2OneOrMore(ParserTestCase):
1005 """Test a Positional with 2 nargs followed by one with one or more"""
1006
1007 argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='+')]
1008 failures = ['', '--foo', 'a', 'a b']
1009 successes = [
1010 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
1011 ]
1012
1013
1014class TestPositionalsNargs2Optional(ParserTestCase):
1015 """Test a Positional with 2 nargs followed by one optional"""
1016
1017 argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='?')]
1018 failures = ['', '--foo', 'a', 'a b c d']
1019 successes = [
1020 ('a b', NS(foo=['a', 'b'], bar=None)),
1021 ('a b c', NS(foo=['a', 'b'], bar='c')),
1022 ]
1023
1024
1025class TestPositionalsNargsZeroOrMore1(ParserTestCase):
1026 """Test a Positional with unlimited nargs followed by one with 1"""
1027
1028 argument_signatures = [Sig('foo', nargs='*'), Sig('bar', nargs=1)]
1029 failures = ['', '--foo', ]
1030 successes = [
1031 ('a', NS(foo=[], bar=['a'])),
1032 ('a b', NS(foo=['a'], bar=['b'])),
1033 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
1034 ]
1035
1036
1037class TestPositionalsNargsOneOrMore1(ParserTestCase):
1038 """Test a Positional with one or more nargs followed by one with 1"""
1039
1040 argument_signatures = [Sig('foo', nargs='+'), Sig('bar', nargs=1)]
1041 failures = ['', '--foo', 'a']
1042 successes = [
1043 ('a b', NS(foo=['a'], bar=['b'])),
1044 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
1045 ]
1046
1047
1048class TestPositionalsNargsOptional1(ParserTestCase):
1049 """Test a Positional with an Optional nargs followed by one with 1"""
1050
1051 argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs=1)]
1052 failures = ['', '--foo', 'a b c']
1053 successes = [
1054 ('a', NS(foo=None, bar=['a'])),
1055 ('a b', NS(foo='a', bar=['b'])),
1056 ]
1057
1058
1059class TestPositionalsNargsNoneZeroOrMore1(ParserTestCase):
1060 """Test three Positionals: no nargs, unlimited nargs and 1 nargs"""
1061
1062 argument_signatures = [
1063 Sig('foo'),
1064 Sig('bar', nargs='*'),
1065 Sig('baz', nargs=1),
1066 ]
1067 failures = ['', '--foo', 'a']
1068 successes = [
1069 ('a b', NS(foo='a', bar=[], baz=['b'])),
1070 ('a b c', NS(foo='a', bar=['b'], baz=['c'])),
1071 ]
1072
1073
1074class TestPositionalsNargsNoneOneOrMore1(ParserTestCase):
1075 """Test three Positionals: no nargs, one or more nargs and 1 nargs"""
1076
1077 argument_signatures = [
1078 Sig('foo'),
1079 Sig('bar', nargs='+'),
1080 Sig('baz', nargs=1),
1081 ]
1082 failures = ['', '--foo', 'a', 'b']
1083 successes = [
1084 ('a b c', NS(foo='a', bar=['b'], baz=['c'])),
1085 ('a b c d', NS(foo='a', bar=['b', 'c'], baz=['d'])),
1086 ]
1087
1088
1089class TestPositionalsNargsNoneOptional1(ParserTestCase):
1090 """Test three Positionals: no nargs, optional narg and 1 nargs"""
1091
1092 argument_signatures = [
1093 Sig('foo'),
1094 Sig('bar', nargs='?', default=0.625),
1095 Sig('baz', nargs=1),
1096 ]
1097 failures = ['', '--foo', 'a']
1098 successes = [
1099 ('a b', NS(foo='a', bar=0.625, baz=['b'])),
1100 ('a b c', NS(foo='a', bar='b', baz=['c'])),
1101 ]
1102
1103
1104class TestPositionalsNargsOptionalOptional(ParserTestCase):
1105 """Test two optional nargs"""
1106
1107 argument_signatures = [
1108 Sig('foo', nargs='?'),
1109 Sig('bar', nargs='?', default=42),
1110 ]
1111 failures = ['--foo', 'a b c']
1112 successes = [
1113 ('', NS(foo=None, bar=42)),
1114 ('a', NS(foo='a', bar=42)),
1115 ('a b', NS(foo='a', bar='b')),
1116 ]
1117
1118
1119class TestPositionalsNargsOptionalZeroOrMore(ParserTestCase):
1120 """Test an Optional narg followed by unlimited nargs"""
1121
1122 argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs='*')]
1123 failures = ['--foo']
1124 successes = [
1125 ('', NS(foo=None, bar=[])),
1126 ('a', NS(foo='a', bar=[])),
1127 ('a b', NS(foo='a', bar=['b'])),
1128 ('a b c', NS(foo='a', bar=['b', 'c'])),
1129 ]
1130
1131
1132class TestPositionalsNargsOptionalOneOrMore(ParserTestCase):
1133 """Test an Optional narg followed by one or more nargs"""
1134
1135 argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs='+')]
1136 failures = ['', '--foo']
1137 successes = [
1138 ('a', NS(foo=None, bar=['a'])),
1139 ('a b', NS(foo='a', bar=['b'])),
1140 ('a b c', NS(foo='a', bar=['b', 'c'])),
1141 ]
1142
1143
1144class TestPositionalsChoicesString(ParserTestCase):
1145 """Test a set of single-character choices"""
1146
1147 argument_signatures = [Sig('spam', choices=set('abcdefg'))]
1148 failures = ['', '--foo', 'h', '42', 'ef']
1149 successes = [
1150 ('a', NS(spam='a')),
1151 ('g', NS(spam='g')),
1152 ]
1153
1154
1155class TestPositionalsChoicesInt(ParserTestCase):
1156 """Test a set of integer choices"""
1157
1158 argument_signatures = [Sig('spam', type=int, choices=range(20))]
1159 failures = ['', '--foo', 'h', '42', 'ef']
1160 successes = [
1161 ('4', NS(spam=4)),
1162 ('15', NS(spam=15)),
1163 ]
1164
1165
1166class TestPositionalsActionAppend(ParserTestCase):
1167 """Test the 'append' action"""
1168
1169 argument_signatures = [
1170 Sig('spam', action='append'),
1171 Sig('spam', action='append', nargs=2),
1172 ]
1173 failures = ['', '--foo', 'a', 'a b', 'a b c d']
1174 successes = [
1175 ('a b c', NS(spam=['a', ['b', 'c']])),
1176 ]
1177
1178# ========================================
1179# Combined optionals and positionals tests
1180# ========================================
1181
1182class TestOptionalsNumericAndPositionals(ParserTestCase):
1183 """Tests negative number args when numeric options are present"""
1184
1185 argument_signatures = [
1186 Sig('x', nargs='?'),
1187 Sig('-4', dest='y', action='store_true'),
1188 ]
1189 failures = ['-2', '-315']
1190 successes = [
1191 ('', NS(x=None, y=False)),
1192 ('a', NS(x='a', y=False)),
1193 ('-4', NS(x=None, y=True)),
1194 ('-4 a', NS(x='a', y=True)),
1195 ]
1196
1197
1198class TestOptionalsAlmostNumericAndPositionals(ParserTestCase):
1199 """Tests negative number args when almost numeric options are present"""
1200
1201 argument_signatures = [
1202 Sig('x', nargs='?'),
1203 Sig('-k4', dest='y', action='store_true'),
1204 ]
1205 failures = ['-k3']
1206 successes = [
1207 ('', NS(x=None, y=False)),
1208 ('-2', NS(x='-2', y=False)),
1209 ('a', NS(x='a', y=False)),
1210 ('-k4', NS(x=None, y=True)),
1211 ('-k4 a', NS(x='a', y=True)),
1212 ]
1213
1214
1215class TestEmptyAndSpaceContainingArguments(ParserTestCase):
1216
1217 argument_signatures = [
1218 Sig('x', nargs='?'),
1219 Sig('-y', '--yyy', dest='y'),
1220 ]
1221 failures = ['-y']
1222 successes = [
1223 ([''], NS(x='', y=None)),
1224 (['a badger'], NS(x='a badger', y=None)),
1225 (['-a badger'], NS(x='-a badger', y=None)),
1226 (['-y', ''], NS(x=None, y='')),
1227 (['-y', 'a badger'], NS(x=None, y='a badger')),
1228 (['-y', '-a badger'], NS(x=None, y='-a badger')),
1229 (['--yyy=a badger'], NS(x=None, y='a badger')),
1230 (['--yyy=-a badger'], NS(x=None, y='-a badger')),
1231 ]
1232
1233
1234class TestPrefixCharacterOnlyArguments(ParserTestCase):
1235
1236 parser_signature = Sig(prefix_chars='-+')
1237 argument_signatures = [
1238 Sig('-', dest='x', nargs='?', const='badger'),
1239 Sig('+', dest='y', type=int, default=42),
1240 Sig('-+-', dest='z', action='store_true'),
1241 ]
1242 failures = ['-y', '+ -']
1243 successes = [
1244 ('', NS(x=None, y=42, z=False)),
1245 ('-', NS(x='badger', y=42, z=False)),
1246 ('- X', NS(x='X', y=42, z=False)),
1247 ('+ -3', NS(x=None, y=-3, z=False)),
1248 ('-+-', NS(x=None, y=42, z=True)),
1249 ('- ===', NS(x='===', y=42, z=False)),
1250 ]
1251
1252
1253class TestNargsZeroOrMore(ParserTestCase):
Martin Pantercc71a792016-04-05 06:19:42 +00001254 """Tests specifying args for an Optional that accepts zero or more"""
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001255
1256 argument_signatures = [Sig('-x', nargs='*'), Sig('y', nargs='*')]
1257 failures = []
1258 successes = [
1259 ('', NS(x=None, y=[])),
1260 ('-x', NS(x=[], y=[])),
1261 ('-x a', NS(x=['a'], y=[])),
1262 ('-x a -- b', NS(x=['a'], y=['b'])),
1263 ('a', NS(x=None, y=['a'])),
1264 ('a -x', NS(x=[], y=['a'])),
1265 ('a -x b', NS(x=['b'], y=['a'])),
1266 ]
1267
1268
1269class TestNargsRemainder(ParserTestCase):
1270 """Tests specifying a positional with nargs=REMAINDER"""
1271
1272 argument_signatures = [Sig('x'), Sig('y', nargs='...'), Sig('-z')]
1273 failures = ['', '-z', '-z Z']
1274 successes = [
1275 ('X', NS(x='X', y=[], z=None)),
1276 ('-z Z X', NS(x='X', y=[], z='Z')),
1277 ('X A B -z Z', NS(x='X', y=['A', 'B', '-z', 'Z'], z=None)),
1278 ('X Y --foo', NS(x='X', y=['Y', '--foo'], z=None)),
1279 ]
1280
1281
1282class TestOptionLike(ParserTestCase):
1283 """Tests options that may or may not be arguments"""
1284
1285 argument_signatures = [
1286 Sig('-x', type=float),
1287 Sig('-3', type=float, dest='y'),
1288 Sig('z', nargs='*'),
1289 ]
1290 failures = ['-x', '-y2.5', '-xa', '-x -a',
1291 '-x -3', '-x -3.5', '-3 -3.5',
1292 '-x -2.5', '-x -2.5 a', '-3 -.5',
1293 'a x -1', '-x -1 a', '-3 -1 a']
1294 successes = [
1295 ('', NS(x=None, y=None, z=[])),
1296 ('-x 2.5', NS(x=2.5, y=None, z=[])),
1297 ('-x 2.5 a', NS(x=2.5, y=None, z=['a'])),
1298 ('-3.5', NS(x=None, y=0.5, z=[])),
1299 ('-3-.5', NS(x=None, y=-0.5, z=[])),
1300 ('-3 .5', NS(x=None, y=0.5, z=[])),
1301 ('a -3.5', NS(x=None, y=0.5, z=['a'])),
1302 ('a', NS(x=None, y=None, z=['a'])),
1303 ('a -x 1', NS(x=1.0, y=None, z=['a'])),
1304 ('-x 1 a', NS(x=1.0, y=None, z=['a'])),
1305 ('-3 1 a', NS(x=None, y=1.0, z=['a'])),
1306 ]
1307
1308
1309class TestDefaultSuppress(ParserTestCase):
1310 """Test actions with suppressed defaults"""
1311
1312 argument_signatures = [
1313 Sig('foo', nargs='?', default=argparse.SUPPRESS),
1314 Sig('bar', nargs='*', default=argparse.SUPPRESS),
1315 Sig('--baz', action='store_true', default=argparse.SUPPRESS),
1316 ]
1317 failures = ['-x']
1318 successes = [
1319 ('', NS()),
1320 ('a', NS(foo='a')),
1321 ('a b', NS(foo='a', bar=['b'])),
1322 ('--baz', NS(baz=True)),
1323 ('a --baz', NS(foo='a', baz=True)),
1324 ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
1325 ]
1326
1327
1328class TestParserDefaultSuppress(ParserTestCase):
1329 """Test actions with a parser-level default of SUPPRESS"""
1330
1331 parser_signature = Sig(argument_default=argparse.SUPPRESS)
1332 argument_signatures = [
1333 Sig('foo', nargs='?'),
1334 Sig('bar', nargs='*'),
1335 Sig('--baz', action='store_true'),
1336 ]
1337 failures = ['-x']
1338 successes = [
1339 ('', NS()),
1340 ('a', NS(foo='a')),
1341 ('a b', NS(foo='a', bar=['b'])),
1342 ('--baz', NS(baz=True)),
1343 ('a --baz', NS(foo='a', baz=True)),
1344 ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
1345 ]
1346
1347
1348class TestParserDefault42(ParserTestCase):
1349 """Test actions with a parser-level default of 42"""
1350
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02001351 parser_signature = Sig(argument_default=42)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001352 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02001353 Sig('--version', action='version', version='1.0'),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001354 Sig('foo', nargs='?'),
1355 Sig('bar', nargs='*'),
1356 Sig('--baz', action='store_true'),
1357 ]
1358 failures = ['-x']
1359 successes = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02001360 ('', NS(foo=42, bar=42, baz=42, version=42)),
1361 ('a', NS(foo='a', bar=42, baz=42, version=42)),
1362 ('a b', NS(foo='a', bar=['b'], baz=42, version=42)),
1363 ('--baz', NS(foo=42, bar=42, baz=True, version=42)),
1364 ('a --baz', NS(foo='a', bar=42, baz=True, version=42)),
1365 ('--baz a b', NS(foo='a', bar=['b'], baz=True, version=42)),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001366 ]
1367
1368
1369class TestArgumentsFromFile(TempDirMixin, ParserTestCase):
1370 """Test reading arguments from a file"""
1371
1372 def setUp(self):
1373 super(TestArgumentsFromFile, self).setUp()
1374 file_texts = [
1375 ('hello', 'hello world!\n'),
1376 ('recursive', '-a\n'
1377 'A\n'
1378 '@hello'),
1379 ('invalid', '@no-such-path\n'),
1380 ]
1381 for path, text in file_texts:
Serhiy Storchaka5b10b982019-03-05 10:06:26 +02001382 with open(path, 'w') as file:
1383 file.write(text)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001384
1385 parser_signature = Sig(fromfile_prefix_chars='@')
1386 argument_signatures = [
1387 Sig('-a'),
1388 Sig('x'),
1389 Sig('y', nargs='+'),
1390 ]
1391 failures = ['', '-b', 'X', '@invalid', '@missing']
1392 successes = [
1393 ('X Y', NS(a=None, x='X', y=['Y'])),
1394 ('X -a A Y Z', NS(a='A', x='X', y=['Y', 'Z'])),
1395 ('@hello X', NS(a=None, x='hello world!', y=['X'])),
1396 ('X @hello', NS(a=None, x='X', y=['hello world!'])),
1397 ('-a B @recursive Y Z', NS(a='A', x='hello world!', y=['Y', 'Z'])),
1398 ('X @recursive Z -a B', NS(a='B', x='X', y=['hello world!', 'Z'])),
R David Murrayb94082a2012-07-21 22:20:11 -04001399 (["-a", "", "X", "Y"], NS(a='', x='X', y=['Y'])),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001400 ]
1401
1402
1403class TestArgumentsFromFileConverter(TempDirMixin, ParserTestCase):
1404 """Test reading arguments from a file"""
1405
1406 def setUp(self):
1407 super(TestArgumentsFromFileConverter, self).setUp()
1408 file_texts = [
1409 ('hello', 'hello world!\n'),
1410 ]
1411 for path, text in file_texts:
Serhiy Storchaka5b10b982019-03-05 10:06:26 +02001412 with open(path, 'w') as file:
1413 file.write(text)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001414
1415 class FromFileConverterArgumentParser(ErrorRaisingArgumentParser):
1416
1417 def convert_arg_line_to_args(self, arg_line):
1418 for arg in arg_line.split():
1419 if not arg.strip():
1420 continue
1421 yield arg
1422 parser_class = FromFileConverterArgumentParser
1423 parser_signature = Sig(fromfile_prefix_chars='@')
1424 argument_signatures = [
1425 Sig('y', nargs='+'),
1426 ]
1427 failures = []
1428 successes = [
1429 ('@hello X', NS(y=['hello', 'world!', 'X'])),
1430 ]
1431
1432
1433# =====================
1434# Type conversion tests
1435# =====================
1436
1437class TestFileTypeRepr(TestCase):
1438
1439 def test_r(self):
1440 type = argparse.FileType('r')
1441 self.assertEqual("FileType('r')", repr(type))
1442
1443 def test_wb_1(self):
1444 type = argparse.FileType('wb', 1)
1445 self.assertEqual("FileType('wb', 1)", repr(type))
1446
Petri Lehtinen74d6c252012-12-15 22:39:32 +02001447 def test_r_latin(self):
1448 type = argparse.FileType('r', encoding='latin_1')
1449 self.assertEqual("FileType('r', encoding='latin_1')", repr(type))
1450
1451 def test_w_big5_ignore(self):
1452 type = argparse.FileType('w', encoding='big5', errors='ignore')
1453 self.assertEqual("FileType('w', encoding='big5', errors='ignore')",
1454 repr(type))
1455
1456 def test_r_1_replace(self):
1457 type = argparse.FileType('r', 1, errors='replace')
1458 self.assertEqual("FileType('r', 1, errors='replace')", repr(type))
1459
Steve Dowerd0f49d22018-09-18 09:10:26 -07001460class StdStreamComparer:
1461 def __init__(self, attr):
1462 self.attr = attr
1463
1464 def __eq__(self, other):
1465 return other == getattr(sys, self.attr)
1466
1467eq_stdin = StdStreamComparer('stdin')
1468eq_stdout = StdStreamComparer('stdout')
1469eq_stderr = StdStreamComparer('stderr')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001470
1471class RFile(object):
1472 seen = {}
1473
1474 def __init__(self, name):
1475 self.name = name
1476
1477 def __eq__(self, other):
1478 if other in self.seen:
1479 text = self.seen[other]
1480 else:
1481 text = self.seen[other] = other.read()
1482 other.close()
1483 if not isinstance(text, str):
1484 text = text.decode('ascii')
1485 return self.name == other.name == text
1486
1487
1488class TestFileTypeR(TempDirMixin, ParserTestCase):
1489 """Test the FileType option/argument type for reading files"""
1490
1491 def setUp(self):
1492 super(TestFileTypeR, self).setUp()
1493 for file_name in ['foo', 'bar']:
Serhiy Storchaka5b10b982019-03-05 10:06:26 +02001494 with open(os.path.join(self.temp_dir, file_name), 'w') as file:
1495 file.write(file_name)
Steven Bethardb0270112011-01-24 21:02:50 +00001496 self.create_readonly_file('readonly')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001497
1498 argument_signatures = [
1499 Sig('-x', type=argparse.FileType()),
1500 Sig('spam', type=argparse.FileType('r')),
1501 ]
Steven Bethardb0270112011-01-24 21:02:50 +00001502 failures = ['-x', '', 'non-existent-file.txt']
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001503 successes = [
1504 ('foo', NS(x=None, spam=RFile('foo'))),
1505 ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
1506 ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
Steve Dowerd0f49d22018-09-18 09:10:26 -07001507 ('-x - -', NS(x=eq_stdin, spam=eq_stdin)),
Steven Bethardb0270112011-01-24 21:02:50 +00001508 ('readonly', NS(x=None, spam=RFile('readonly'))),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001509 ]
1510
R David Murray6fb8fb12012-08-31 22:45:20 -04001511class TestFileTypeDefaults(TempDirMixin, ParserTestCase):
1512 """Test that a file is not created unless the default is needed"""
1513 def setUp(self):
1514 super(TestFileTypeDefaults, self).setUp()
1515 file = open(os.path.join(self.temp_dir, 'good'), 'w')
1516 file.write('good')
1517 file.close()
1518
1519 argument_signatures = [
1520 Sig('-c', type=argparse.FileType('r'), default='no-file.txt'),
1521 ]
1522 # should provoke no such file error
1523 failures = ['']
1524 # should not provoke error because default file is created
1525 successes = [('-c good', NS(c=RFile('good')))]
1526
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001527
1528class TestFileTypeRB(TempDirMixin, ParserTestCase):
1529 """Test the FileType option/argument type for reading files"""
1530
1531 def setUp(self):
1532 super(TestFileTypeRB, self).setUp()
1533 for file_name in ['foo', 'bar']:
Serhiy Storchaka5b10b982019-03-05 10:06:26 +02001534 with open(os.path.join(self.temp_dir, file_name), 'w') as file:
1535 file.write(file_name)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001536
1537 argument_signatures = [
1538 Sig('-x', type=argparse.FileType('rb')),
1539 Sig('spam', type=argparse.FileType('rb')),
1540 ]
1541 failures = ['-x', '']
1542 successes = [
1543 ('foo', NS(x=None, spam=RFile('foo'))),
1544 ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
1545 ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
Steve Dowerd0f49d22018-09-18 09:10:26 -07001546 ('-x - -', NS(x=eq_stdin, spam=eq_stdin)),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001547 ]
1548
1549
1550class WFile(object):
1551 seen = set()
1552
1553 def __init__(self, name):
1554 self.name = name
1555
1556 def __eq__(self, other):
1557 if other not in self.seen:
1558 text = 'Check that file is writable.'
1559 if 'b' in other.mode:
1560 text = text.encode('ascii')
1561 other.write(text)
1562 other.close()
1563 self.seen.add(other)
1564 return self.name == other.name
1565
1566
Victor Stinnera04b39b2011-11-20 23:09:09 +01001567@unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1568 "non-root user required")
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001569class TestFileTypeW(TempDirMixin, ParserTestCase):
1570 """Test the FileType option/argument type for writing files"""
1571
Steven Bethardb0270112011-01-24 21:02:50 +00001572 def setUp(self):
1573 super(TestFileTypeW, self).setUp()
1574 self.create_readonly_file('readonly')
1575
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001576 argument_signatures = [
1577 Sig('-x', type=argparse.FileType('w')),
1578 Sig('spam', type=argparse.FileType('w')),
1579 ]
Steven Bethardb0270112011-01-24 21:02:50 +00001580 failures = ['-x', '', 'readonly']
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001581 successes = [
1582 ('foo', NS(x=None, spam=WFile('foo'))),
1583 ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
1584 ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
Steve Dowerd0f49d22018-09-18 09:10:26 -07001585 ('-x - -', NS(x=eq_stdout, spam=eq_stdout)),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001586 ]
1587
1588
1589class TestFileTypeWB(TempDirMixin, ParserTestCase):
1590
1591 argument_signatures = [
1592 Sig('-x', type=argparse.FileType('wb')),
1593 Sig('spam', type=argparse.FileType('wb')),
1594 ]
1595 failures = ['-x', '']
1596 successes = [
1597 ('foo', NS(x=None, spam=WFile('foo'))),
1598 ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
1599 ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
Steve Dowerd0f49d22018-09-18 09:10:26 -07001600 ('-x - -', NS(x=eq_stdout, spam=eq_stdout)),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001601 ]
1602
1603
Petri Lehtinen74d6c252012-12-15 22:39:32 +02001604class TestFileTypeOpenArgs(TestCase):
1605 """Test that open (the builtin) is correctly called"""
1606
1607 def test_open_args(self):
1608 FT = argparse.FileType
1609 cases = [
1610 (FT('rb'), ('rb', -1, None, None)),
1611 (FT('w', 1), ('w', 1, None, None)),
1612 (FT('w', errors='replace'), ('w', -1, None, 'replace')),
1613 (FT('wb', encoding='big5'), ('wb', -1, 'big5', None)),
1614 (FT('w', 0, 'l1', 'strict'), ('w', 0, 'l1', 'strict')),
1615 ]
1616 with mock.patch('builtins.open') as m:
1617 for type, args in cases:
1618 type('foo')
1619 m.assert_called_with('foo', *args)
1620
1621
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001622class TestTypeCallable(ParserTestCase):
1623 """Test some callables as option/argument types"""
1624
1625 argument_signatures = [
1626 Sig('--eggs', type=complex),
1627 Sig('spam', type=float),
1628 ]
1629 failures = ['a', '42j', '--eggs a', '--eggs 2i']
1630 successes = [
1631 ('--eggs=42 42', NS(eggs=42, spam=42.0)),
1632 ('--eggs 2j -- -1.5', NS(eggs=2j, spam=-1.5)),
1633 ('1024.675', NS(eggs=None, spam=1024.675)),
1634 ]
1635
1636
1637class TestTypeUserDefined(ParserTestCase):
1638 """Test a user-defined option/argument type"""
1639
1640 class MyType(TestCase):
1641
1642 def __init__(self, value):
1643 self.value = value
1644
1645 def __eq__(self, other):
1646 return (type(self), self.value) == (type(other), other.value)
1647
1648 argument_signatures = [
1649 Sig('-x', type=MyType),
1650 Sig('spam', type=MyType),
1651 ]
1652 failures = []
1653 successes = [
1654 ('a -x b', NS(x=MyType('b'), spam=MyType('a'))),
1655 ('-xf g', NS(x=MyType('f'), spam=MyType('g'))),
1656 ]
1657
1658
1659class TestTypeClassicClass(ParserTestCase):
1660 """Test a classic class type"""
1661
1662 class C:
1663
1664 def __init__(self, value):
1665 self.value = value
1666
1667 def __eq__(self, other):
1668 return (type(self), self.value) == (type(other), other.value)
1669
1670 argument_signatures = [
1671 Sig('-x', type=C),
1672 Sig('spam', type=C),
1673 ]
1674 failures = []
1675 successes = [
1676 ('a -x b', NS(x=C('b'), spam=C('a'))),
1677 ('-xf g', NS(x=C('f'), spam=C('g'))),
1678 ]
1679
1680
1681class TestTypeRegistration(TestCase):
1682 """Test a user-defined type by registering it"""
1683
1684 def test(self):
1685
1686 def get_my_type(string):
1687 return 'my_type{%s}' % string
1688
1689 parser = argparse.ArgumentParser()
1690 parser.register('type', 'my_type', get_my_type)
1691 parser.add_argument('-x', type='my_type')
1692 parser.add_argument('y', type='my_type')
1693
1694 self.assertEqual(parser.parse_args('1'.split()),
1695 NS(x=None, y='my_type{1}'))
1696 self.assertEqual(parser.parse_args('-x 1 42'.split()),
1697 NS(x='my_type{1}', y='my_type{42}'))
1698
1699
1700# ============
1701# Action tests
1702# ============
1703
1704class TestActionUserDefined(ParserTestCase):
1705 """Test a user-defined option/argument action"""
1706
1707 class OptionalAction(argparse.Action):
1708
1709 def __call__(self, parser, namespace, value, option_string=None):
1710 try:
1711 # check destination and option string
1712 assert self.dest == 'spam', 'dest: %s' % self.dest
1713 assert option_string == '-s', 'flag: %s' % option_string
1714 # when option is before argument, badger=2, and when
1715 # option is after argument, badger=<whatever was set>
1716 expected_ns = NS(spam=0.25)
1717 if value in [0.125, 0.625]:
1718 expected_ns.badger = 2
1719 elif value in [2.0]:
1720 expected_ns.badger = 84
1721 else:
1722 raise AssertionError('value: %s' % value)
1723 assert expected_ns == namespace, ('expected %s, got %s' %
1724 (expected_ns, namespace))
1725 except AssertionError:
1726 e = sys.exc_info()[1]
1727 raise ArgumentParserError('opt_action failed: %s' % e)
1728 setattr(namespace, 'spam', value)
1729
1730 class PositionalAction(argparse.Action):
1731
1732 def __call__(self, parser, namespace, value, option_string=None):
1733 try:
1734 assert option_string is None, ('option_string: %s' %
1735 option_string)
1736 # check destination
1737 assert self.dest == 'badger', 'dest: %s' % self.dest
1738 # when argument is before option, spam=0.25, and when
1739 # option is after argument, spam=<whatever was set>
1740 expected_ns = NS(badger=2)
1741 if value in [42, 84]:
1742 expected_ns.spam = 0.25
1743 elif value in [1]:
1744 expected_ns.spam = 0.625
1745 elif value in [2]:
1746 expected_ns.spam = 0.125
1747 else:
1748 raise AssertionError('value: %s' % value)
1749 assert expected_ns == namespace, ('expected %s, got %s' %
1750 (expected_ns, namespace))
1751 except AssertionError:
1752 e = sys.exc_info()[1]
1753 raise ArgumentParserError('arg_action failed: %s' % e)
1754 setattr(namespace, 'badger', value)
1755
1756 argument_signatures = [
1757 Sig('-s', dest='spam', action=OptionalAction,
1758 type=float, default=0.25),
1759 Sig('badger', action=PositionalAction,
1760 type=int, nargs='?', default=2),
1761 ]
1762 failures = []
1763 successes = [
1764 ('-s0.125', NS(spam=0.125, badger=2)),
1765 ('42', NS(spam=0.25, badger=42)),
1766 ('-s 0.625 1', NS(spam=0.625, badger=1)),
1767 ('84 -s2', NS(spam=2.0, badger=84)),
1768 ]
1769
1770
1771class TestActionRegistration(TestCase):
1772 """Test a user-defined action supplied by registering it"""
1773
1774 class MyAction(argparse.Action):
1775
1776 def __call__(self, parser, namespace, values, option_string=None):
1777 setattr(namespace, self.dest, 'foo[%s]' % values)
1778
1779 def test(self):
1780
1781 parser = argparse.ArgumentParser()
1782 parser.register('action', 'my_action', self.MyAction)
1783 parser.add_argument('badger', action='my_action')
1784
1785 self.assertEqual(parser.parse_args(['1']), NS(badger='foo[1]'))
1786 self.assertEqual(parser.parse_args(['42']), NS(badger='foo[42]'))
1787
1788
Batuhan Taşkayaaa32a7e2019-05-21 20:47:42 +03001789class TestActionExtend(ParserTestCase):
1790 argument_signatures = [
1791 Sig('--foo', action="extend", nargs="+", type=str),
1792 ]
1793 failures = ()
1794 successes = [
1795 ('--foo f1 --foo f2 f3 f4', NS(foo=['f1', 'f2', 'f3', 'f4'])),
1796 ]
1797
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001798# ================
1799# Subparsers tests
1800# ================
1801
1802class TestAddSubparsers(TestCase):
1803 """Test the add_subparsers method"""
1804
1805 def assertArgumentParserError(self, *args, **kwargs):
1806 self.assertRaises(ArgumentParserError, *args, **kwargs)
1807
Steven Bethardfd311a72010-12-18 11:19:23 +00001808 def _get_parser(self, subparser_help=False, prefix_chars=None,
1809 aliases=False):
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001810 # create a parser with a subparsers argument
R. David Murray88c49fe2010-08-03 17:56:09 +00001811 if prefix_chars:
1812 parser = ErrorRaisingArgumentParser(
1813 prog='PROG', description='main description', prefix_chars=prefix_chars)
1814 parser.add_argument(
1815 prefix_chars[0] * 2 + 'foo', action='store_true', help='foo help')
1816 else:
1817 parser = ErrorRaisingArgumentParser(
1818 prog='PROG', description='main description')
1819 parser.add_argument(
1820 '--foo', action='store_true', help='foo help')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001821 parser.add_argument(
1822 'bar', type=float, help='bar help')
1823
1824 # check that only one subparsers argument can be added
Anthony Sottileaaf6fc02017-09-20 14:35:27 -07001825 subparsers_kwargs = {'required': False}
Steven Bethardfd311a72010-12-18 11:19:23 +00001826 if aliases:
1827 subparsers_kwargs['metavar'] = 'COMMAND'
1828 subparsers_kwargs['title'] = 'commands'
1829 else:
1830 subparsers_kwargs['help'] = 'command help'
1831 subparsers = parser.add_subparsers(**subparsers_kwargs)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001832 self.assertArgumentParserError(parser.add_subparsers)
1833
1834 # add first sub-parser
1835 parser1_kwargs = dict(description='1 description')
1836 if subparser_help:
1837 parser1_kwargs['help'] = '1 help'
Steven Bethardfd311a72010-12-18 11:19:23 +00001838 if aliases:
1839 parser1_kwargs['aliases'] = ['1alias1', '1alias2']
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001840 parser1 = subparsers.add_parser('1', **parser1_kwargs)
1841 parser1.add_argument('-w', type=int, help='w help')
1842 parser1.add_argument('x', choices='abc', help='x help')
1843
1844 # add second sub-parser
1845 parser2_kwargs = dict(description='2 description')
1846 if subparser_help:
1847 parser2_kwargs['help'] = '2 help'
1848 parser2 = subparsers.add_parser('2', **parser2_kwargs)
1849 parser2.add_argument('-y', choices='123', help='y help')
1850 parser2.add_argument('z', type=complex, nargs='*', help='z help')
1851
R David Murray00528e82012-07-21 22:48:35 -04001852 # add third sub-parser
1853 parser3_kwargs = dict(description='3 description')
1854 if subparser_help:
1855 parser3_kwargs['help'] = '3 help'
1856 parser3 = subparsers.add_parser('3', **parser3_kwargs)
1857 parser3.add_argument('t', type=int, help='t help')
1858 parser3.add_argument('u', nargs='...', help='u help')
1859
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001860 # return the main parser
1861 return parser
1862
1863 def setUp(self):
Steven Bethard1f1c2472010-11-01 13:56:09 +00001864 super().setUp()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001865 self.parser = self._get_parser()
1866 self.command_help_parser = self._get_parser(subparser_help=True)
1867
1868 def test_parse_args_failures(self):
1869 # check some failure cases:
1870 for args_str in ['', 'a', 'a a', '0.5 a', '0.5 1',
1871 '0.5 1 -y', '0.5 2 -w']:
1872 args = args_str.split()
1873 self.assertArgumentParserError(self.parser.parse_args, args)
1874
1875 def test_parse_args(self):
1876 # check some non-failure cases:
1877 self.assertEqual(
1878 self.parser.parse_args('0.5 1 b -w 7'.split()),
1879 NS(foo=False, bar=0.5, w=7, x='b'),
1880 )
1881 self.assertEqual(
1882 self.parser.parse_args('0.25 --foo 2 -y 2 3j -- -1j'.split()),
1883 NS(foo=True, bar=0.25, y='2', z=[3j, -1j]),
1884 )
1885 self.assertEqual(
1886 self.parser.parse_args('--foo 0.125 1 c'.split()),
1887 NS(foo=True, bar=0.125, w=None, x='c'),
1888 )
R David Murray00528e82012-07-21 22:48:35 -04001889 self.assertEqual(
1890 self.parser.parse_args('-1.5 3 11 -- a --foo 7 -- b'.split()),
1891 NS(foo=False, bar=-1.5, t=11, u=['a', '--foo', '7', '--', 'b']),
1892 )
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001893
Steven Bethardfca2e8a2010-11-02 12:47:22 +00001894 def test_parse_known_args(self):
1895 self.assertEqual(
1896 self.parser.parse_known_args('0.5 1 b -w 7'.split()),
1897 (NS(foo=False, bar=0.5, w=7, x='b'), []),
1898 )
1899 self.assertEqual(
1900 self.parser.parse_known_args('0.5 -p 1 b -w 7'.split()),
1901 (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
1902 )
1903 self.assertEqual(
1904 self.parser.parse_known_args('0.5 1 b -w 7 -p'.split()),
1905 (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
1906 )
1907 self.assertEqual(
1908 self.parser.parse_known_args('0.5 1 b -q -rs -w 7'.split()),
1909 (NS(foo=False, bar=0.5, w=7, x='b'), ['-q', '-rs']),
1910 )
1911 self.assertEqual(
1912 self.parser.parse_known_args('0.5 -W 1 b -X Y -w 7 Z'.split()),
1913 (NS(foo=False, bar=0.5, w=7, x='b'), ['-W', '-X', 'Y', 'Z']),
1914 )
1915
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001916 def test_dest(self):
1917 parser = ErrorRaisingArgumentParser()
1918 parser.add_argument('--foo', action='store_true')
1919 subparsers = parser.add_subparsers(dest='bar')
1920 parser1 = subparsers.add_parser('1')
1921 parser1.add_argument('baz')
1922 self.assertEqual(NS(foo=False, bar='1', baz='2'),
1923 parser.parse_args('1 2'.split()))
1924
Anthony Sottileaaf6fc02017-09-20 14:35:27 -07001925 def _test_required_subparsers(self, parser):
1926 # Should parse the sub command
1927 ret = parser.parse_args(['run'])
1928 self.assertEqual(ret.command, 'run')
1929
1930 # Error when the command is missing
1931 self.assertArgumentParserError(parser.parse_args, ())
1932
1933 def test_required_subparsers_via_attribute(self):
1934 parser = ErrorRaisingArgumentParser()
1935 subparsers = parser.add_subparsers(dest='command')
1936 subparsers.required = True
1937 subparsers.add_parser('run')
1938 self._test_required_subparsers(parser)
1939
1940 def test_required_subparsers_via_kwarg(self):
1941 parser = ErrorRaisingArgumentParser()
1942 subparsers = parser.add_subparsers(dest='command', required=True)
1943 subparsers.add_parser('run')
1944 self._test_required_subparsers(parser)
1945
1946 def test_required_subparsers_default(self):
1947 parser = ErrorRaisingArgumentParser()
1948 subparsers = parser.add_subparsers(dest='command')
1949 subparsers.add_parser('run')
Ned Deily8ebf5ce2018-05-23 21:55:15 -04001950 # No error here
1951 ret = parser.parse_args(())
1952 self.assertIsNone(ret.command)
Anthony Sottileaaf6fc02017-09-20 14:35:27 -07001953
1954 def test_optional_subparsers(self):
1955 parser = ErrorRaisingArgumentParser()
1956 subparsers = parser.add_subparsers(dest='command', required=False)
1957 subparsers.add_parser('run')
1958 # No error here
1959 ret = parser.parse_args(())
1960 self.assertIsNone(ret.command)
1961
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001962 def test_help(self):
1963 self.assertEqual(self.parser.format_usage(),
Vinay Sajip9ae50502016-08-23 08:43:16 +01001964 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001965 self.assertEqual(self.parser.format_help(), textwrap.dedent('''\
Vinay Sajip9ae50502016-08-23 08:43:16 +01001966 usage: PROG [-h] [--foo] bar {1,2,3} ...
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001967
1968 main description
1969
1970 positional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01001971 bar bar help
1972 {1,2,3} command help
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001973
1974 optional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01001975 -h, --help show this help message and exit
1976 --foo foo help
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001977 '''))
1978
R. David Murray88c49fe2010-08-03 17:56:09 +00001979 def test_help_extra_prefix_chars(self):
1980 # Make sure - is still used for help if it is a non-first prefix char
1981 parser = self._get_parser(prefix_chars='+:-')
1982 self.assertEqual(parser.format_usage(),
Vinay Sajip9ae50502016-08-23 08:43:16 +01001983 'usage: PROG [-h] [++foo] bar {1,2,3} ...\n')
R. David Murray88c49fe2010-08-03 17:56:09 +00001984 self.assertEqual(parser.format_help(), textwrap.dedent('''\
Vinay Sajip9ae50502016-08-23 08:43:16 +01001985 usage: PROG [-h] [++foo] bar {1,2,3} ...
R. David Murray88c49fe2010-08-03 17:56:09 +00001986
1987 main description
1988
1989 positional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01001990 bar bar help
1991 {1,2,3} command help
R. David Murray88c49fe2010-08-03 17:56:09 +00001992
1993 optional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01001994 -h, --help show this help message and exit
1995 ++foo foo help
R. David Murray88c49fe2010-08-03 17:56:09 +00001996 '''))
1997
Xiang Zhang7fe28ad2017-01-22 14:37:22 +08001998 def test_help_non_breaking_spaces(self):
1999 parser = ErrorRaisingArgumentParser(
2000 prog='PROG', description='main description')
2001 parser.add_argument(
2002 "--non-breaking", action='store_false',
2003 help='help message containing non-breaking spaces shall not '
2004 'wrap\N{NO-BREAK SPACE}at non-breaking spaces')
2005 self.assertEqual(parser.format_help(), textwrap.dedent('''\
2006 usage: PROG [-h] [--non-breaking]
2007
2008 main description
2009
2010 optional arguments:
2011 -h, --help show this help message and exit
2012 --non-breaking help message containing non-breaking spaces shall not
2013 wrap\N{NO-BREAK SPACE}at non-breaking spaces
2014 '''))
R. David Murray88c49fe2010-08-03 17:56:09 +00002015
2016 def test_help_alternate_prefix_chars(self):
2017 parser = self._get_parser(prefix_chars='+:/')
2018 self.assertEqual(parser.format_usage(),
Vinay Sajip9ae50502016-08-23 08:43:16 +01002019 'usage: PROG [+h] [++foo] bar {1,2,3} ...\n')
R. David Murray88c49fe2010-08-03 17:56:09 +00002020 self.assertEqual(parser.format_help(), textwrap.dedent('''\
Vinay Sajip9ae50502016-08-23 08:43:16 +01002021 usage: PROG [+h] [++foo] bar {1,2,3} ...
R. David Murray88c49fe2010-08-03 17:56:09 +00002022
2023 main description
2024
2025 positional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01002026 bar bar help
2027 {1,2,3} command help
R. David Murray88c49fe2010-08-03 17:56:09 +00002028
2029 optional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01002030 +h, ++help show this help message and exit
2031 ++foo foo help
R. David Murray88c49fe2010-08-03 17:56:09 +00002032 '''))
2033
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002034 def test_parser_command_help(self):
2035 self.assertEqual(self.command_help_parser.format_usage(),
Vinay Sajip9ae50502016-08-23 08:43:16 +01002036 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002037 self.assertEqual(self.command_help_parser.format_help(),
2038 textwrap.dedent('''\
Vinay Sajip9ae50502016-08-23 08:43:16 +01002039 usage: PROG [-h] [--foo] bar {1,2,3} ...
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002040
2041 main description
2042
2043 positional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01002044 bar bar help
2045 {1,2,3} command help
2046 1 1 help
2047 2 2 help
2048 3 3 help
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002049
2050 optional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01002051 -h, --help show this help message and exit
2052 --foo foo help
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002053 '''))
2054
2055 def test_subparser_title_help(self):
2056 parser = ErrorRaisingArgumentParser(prog='PROG',
2057 description='main description')
2058 parser.add_argument('--foo', action='store_true', help='foo help')
2059 parser.add_argument('bar', help='bar help')
2060 subparsers = parser.add_subparsers(title='subcommands',
2061 description='command help',
2062 help='additional text')
2063 parser1 = subparsers.add_parser('1')
2064 parser2 = subparsers.add_parser('2')
2065 self.assertEqual(parser.format_usage(),
2066 'usage: PROG [-h] [--foo] bar {1,2} ...\n')
2067 self.assertEqual(parser.format_help(), textwrap.dedent('''\
2068 usage: PROG [-h] [--foo] bar {1,2} ...
2069
2070 main description
2071
2072 positional arguments:
2073 bar bar help
2074
2075 optional arguments:
2076 -h, --help show this help message and exit
2077 --foo foo help
2078
2079 subcommands:
2080 command help
2081
2082 {1,2} additional text
2083 '''))
2084
2085 def _test_subparser_help(self, args_str, expected_help):
Berker Peksag1c5f56a2014-07-06 09:33:20 +03002086 with self.assertRaises(ArgumentParserError) as cm:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002087 self.parser.parse_args(args_str.split())
Berker Peksag1c5f56a2014-07-06 09:33:20 +03002088 self.assertEqual(expected_help, cm.exception.stdout)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002089
2090 def test_subparser1_help(self):
2091 self._test_subparser_help('5.0 1 -h', textwrap.dedent('''\
2092 usage: PROG bar 1 [-h] [-w W] {a,b,c}
2093
2094 1 description
2095
2096 positional arguments:
2097 {a,b,c} x help
2098
2099 optional arguments:
2100 -h, --help show this help message and exit
2101 -w W w help
2102 '''))
2103
2104 def test_subparser2_help(self):
2105 self._test_subparser_help('5.0 2 -h', textwrap.dedent('''\
2106 usage: PROG bar 2 [-h] [-y {1,2,3}] [z [z ...]]
2107
2108 2 description
2109
2110 positional arguments:
2111 z z help
2112
2113 optional arguments:
2114 -h, --help show this help message and exit
2115 -y {1,2,3} y help
2116 '''))
2117
Steven Bethardfd311a72010-12-18 11:19:23 +00002118 def test_alias_invocation(self):
2119 parser = self._get_parser(aliases=True)
2120 self.assertEqual(
2121 parser.parse_known_args('0.5 1alias1 b'.split()),
2122 (NS(foo=False, bar=0.5, w=None, x='b'), []),
2123 )
2124 self.assertEqual(
2125 parser.parse_known_args('0.5 1alias2 b'.split()),
2126 (NS(foo=False, bar=0.5, w=None, x='b'), []),
2127 )
2128
2129 def test_error_alias_invocation(self):
2130 parser = self._get_parser(aliases=True)
2131 self.assertArgumentParserError(parser.parse_args,
2132 '0.5 1alias3 b'.split())
2133
2134 def test_alias_help(self):
2135 parser = self._get_parser(aliases=True, subparser_help=True)
2136 self.maxDiff = None
2137 self.assertEqual(parser.format_help(), textwrap.dedent("""\
2138 usage: PROG [-h] [--foo] bar COMMAND ...
2139
2140 main description
2141
2142 positional arguments:
2143 bar bar help
2144
2145 optional arguments:
2146 -h, --help show this help message and exit
2147 --foo foo help
2148
2149 commands:
2150 COMMAND
2151 1 (1alias1, 1alias2)
2152 1 help
2153 2 2 help
R David Murray00528e82012-07-21 22:48:35 -04002154 3 3 help
Steven Bethardfd311a72010-12-18 11:19:23 +00002155 """))
2156
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002157# ============
2158# Groups tests
2159# ============
2160
2161class TestPositionalsGroups(TestCase):
2162 """Tests that order of group positionals matches construction order"""
2163
2164 def test_nongroup_first(self):
2165 parser = ErrorRaisingArgumentParser()
2166 parser.add_argument('foo')
2167 group = parser.add_argument_group('g')
2168 group.add_argument('bar')
2169 parser.add_argument('baz')
2170 expected = NS(foo='1', bar='2', baz='3')
2171 result = parser.parse_args('1 2 3'.split())
2172 self.assertEqual(expected, result)
2173
2174 def test_group_first(self):
2175 parser = ErrorRaisingArgumentParser()
2176 group = parser.add_argument_group('xxx')
2177 group.add_argument('foo')
2178 parser.add_argument('bar')
2179 parser.add_argument('baz')
2180 expected = NS(foo='1', bar='2', baz='3')
2181 result = parser.parse_args('1 2 3'.split())
2182 self.assertEqual(expected, result)
2183
2184 def test_interleaved_groups(self):
2185 parser = ErrorRaisingArgumentParser()
2186 group = parser.add_argument_group('xxx')
2187 parser.add_argument('foo')
2188 group.add_argument('bar')
2189 parser.add_argument('baz')
2190 group = parser.add_argument_group('yyy')
2191 group.add_argument('frell')
2192 expected = NS(foo='1', bar='2', baz='3', frell='4')
2193 result = parser.parse_args('1 2 3 4'.split())
2194 self.assertEqual(expected, result)
2195
2196# ===================
2197# Parent parser tests
2198# ===================
2199
2200class TestParentParsers(TestCase):
2201 """Tests that parsers can be created with parent parsers"""
2202
2203 def assertArgumentParserError(self, *args, **kwargs):
2204 self.assertRaises(ArgumentParserError, *args, **kwargs)
2205
2206 def setUp(self):
Steven Bethard1f1c2472010-11-01 13:56:09 +00002207 super().setUp()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002208 self.wxyz_parent = ErrorRaisingArgumentParser(add_help=False)
2209 self.wxyz_parent.add_argument('--w')
2210 x_group = self.wxyz_parent.add_argument_group('x')
2211 x_group.add_argument('-y')
2212 self.wxyz_parent.add_argument('z')
2213
2214 self.abcd_parent = ErrorRaisingArgumentParser(add_help=False)
2215 self.abcd_parent.add_argument('a')
2216 self.abcd_parent.add_argument('-b')
2217 c_group = self.abcd_parent.add_argument_group('c')
2218 c_group.add_argument('--d')
2219
2220 self.w_parent = ErrorRaisingArgumentParser(add_help=False)
2221 self.w_parent.add_argument('--w')
2222
2223 self.z_parent = ErrorRaisingArgumentParser(add_help=False)
2224 self.z_parent.add_argument('z')
2225
2226 # parents with mutually exclusive groups
2227 self.ab_mutex_parent = ErrorRaisingArgumentParser(add_help=False)
2228 group = self.ab_mutex_parent.add_mutually_exclusive_group()
2229 group.add_argument('-a', action='store_true')
2230 group.add_argument('-b', action='store_true')
2231
2232 self.main_program = os.path.basename(sys.argv[0])
2233
2234 def test_single_parent(self):
2235 parser = ErrorRaisingArgumentParser(parents=[self.wxyz_parent])
2236 self.assertEqual(parser.parse_args('-y 1 2 --w 3'.split()),
2237 NS(w='3', y='1', z='2'))
2238
2239 def test_single_parent_mutex(self):
2240 self._test_mutex_ab(self.ab_mutex_parent.parse_args)
2241 parser = ErrorRaisingArgumentParser(parents=[self.ab_mutex_parent])
2242 self._test_mutex_ab(parser.parse_args)
2243
2244 def test_single_granparent_mutex(self):
2245 parents = [self.ab_mutex_parent]
2246 parser = ErrorRaisingArgumentParser(add_help=False, parents=parents)
2247 parser = ErrorRaisingArgumentParser(parents=[parser])
2248 self._test_mutex_ab(parser.parse_args)
2249
2250 def _test_mutex_ab(self, parse_args):
2251 self.assertEqual(parse_args([]), NS(a=False, b=False))
2252 self.assertEqual(parse_args(['-a']), NS(a=True, b=False))
2253 self.assertEqual(parse_args(['-b']), NS(a=False, b=True))
2254 self.assertArgumentParserError(parse_args, ['-a', '-b'])
2255 self.assertArgumentParserError(parse_args, ['-b', '-a'])
2256 self.assertArgumentParserError(parse_args, ['-c'])
2257 self.assertArgumentParserError(parse_args, ['-a', '-c'])
2258 self.assertArgumentParserError(parse_args, ['-b', '-c'])
2259
2260 def test_multiple_parents(self):
2261 parents = [self.abcd_parent, self.wxyz_parent]
2262 parser = ErrorRaisingArgumentParser(parents=parents)
2263 self.assertEqual(parser.parse_args('--d 1 --w 2 3 4'.split()),
2264 NS(a='3', b=None, d='1', w='2', y=None, z='4'))
2265
2266 def test_multiple_parents_mutex(self):
2267 parents = [self.ab_mutex_parent, self.wxyz_parent]
2268 parser = ErrorRaisingArgumentParser(parents=parents)
2269 self.assertEqual(parser.parse_args('-a --w 2 3'.split()),
2270 NS(a=True, b=False, w='2', y=None, z='3'))
2271 self.assertArgumentParserError(
2272 parser.parse_args, '-a --w 2 3 -b'.split())
2273 self.assertArgumentParserError(
2274 parser.parse_args, '-a -b --w 2 3'.split())
2275
2276 def test_conflicting_parents(self):
2277 self.assertRaises(
2278 argparse.ArgumentError,
2279 argparse.ArgumentParser,
2280 parents=[self.w_parent, self.wxyz_parent])
2281
2282 def test_conflicting_parents_mutex(self):
2283 self.assertRaises(
2284 argparse.ArgumentError,
2285 argparse.ArgumentParser,
2286 parents=[self.abcd_parent, self.ab_mutex_parent])
2287
2288 def test_same_argument_name_parents(self):
2289 parents = [self.wxyz_parent, self.z_parent]
2290 parser = ErrorRaisingArgumentParser(parents=parents)
2291 self.assertEqual(parser.parse_args('1 2'.split()),
2292 NS(w=None, y=None, z='2'))
2293
2294 def test_subparser_parents(self):
2295 parser = ErrorRaisingArgumentParser()
2296 subparsers = parser.add_subparsers()
2297 abcde_parser = subparsers.add_parser('bar', parents=[self.abcd_parent])
2298 abcde_parser.add_argument('e')
2299 self.assertEqual(parser.parse_args('bar -b 1 --d 2 3 4'.split()),
2300 NS(a='3', b='1', d='2', e='4'))
2301
2302 def test_subparser_parents_mutex(self):
2303 parser = ErrorRaisingArgumentParser()
2304 subparsers = parser.add_subparsers()
2305 parents = [self.ab_mutex_parent]
2306 abc_parser = subparsers.add_parser('foo', parents=parents)
2307 c_group = abc_parser.add_argument_group('c_group')
2308 c_group.add_argument('c')
2309 parents = [self.wxyz_parent, self.ab_mutex_parent]
2310 wxyzabe_parser = subparsers.add_parser('bar', parents=parents)
2311 wxyzabe_parser.add_argument('e')
2312 self.assertEqual(parser.parse_args('foo -a 4'.split()),
2313 NS(a=True, b=False, c='4'))
2314 self.assertEqual(parser.parse_args('bar -b --w 2 3 4'.split()),
2315 NS(a=False, b=True, w='2', y=None, z='3', e='4'))
2316 self.assertArgumentParserError(
2317 parser.parse_args, 'foo -a -b 4'.split())
2318 self.assertArgumentParserError(
2319 parser.parse_args, 'bar -b -a 4'.split())
2320
2321 def test_parent_help(self):
2322 parents = [self.abcd_parent, self.wxyz_parent]
2323 parser = ErrorRaisingArgumentParser(parents=parents)
2324 parser_help = parser.format_help()
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002325 progname = self.main_program
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002326 self.assertEqual(parser_help, textwrap.dedent('''\
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002327 usage: {}{}[-h] [-b B] [--d D] [--w W] [-y Y] a z
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002328
2329 positional arguments:
2330 a
2331 z
2332
2333 optional arguments:
2334 -h, --help show this help message and exit
2335 -b B
2336 --w W
2337
2338 c:
2339 --d D
2340
2341 x:
2342 -y Y
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002343 '''.format(progname, ' ' if progname else '' )))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002344
2345 def test_groups_parents(self):
2346 parent = ErrorRaisingArgumentParser(add_help=False)
2347 g = parent.add_argument_group(title='g', description='gd')
2348 g.add_argument('-w')
2349 g.add_argument('-x')
2350 m = parent.add_mutually_exclusive_group()
2351 m.add_argument('-y')
2352 m.add_argument('-z')
2353 parser = ErrorRaisingArgumentParser(parents=[parent])
2354
2355 self.assertRaises(ArgumentParserError, parser.parse_args,
2356 ['-y', 'Y', '-z', 'Z'])
2357
2358 parser_help = parser.format_help()
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002359 progname = self.main_program
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002360 self.assertEqual(parser_help, textwrap.dedent('''\
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002361 usage: {}{}[-h] [-w W] [-x X] [-y Y | -z Z]
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002362
2363 optional arguments:
2364 -h, --help show this help message and exit
2365 -y Y
2366 -z Z
2367
2368 g:
2369 gd
2370
2371 -w W
2372 -x X
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002373 '''.format(progname, ' ' if progname else '' )))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002374
2375# ==============================
2376# Mutually exclusive group tests
2377# ==============================
2378
2379class TestMutuallyExclusiveGroupErrors(TestCase):
2380
2381 def test_invalid_add_argument_group(self):
2382 parser = ErrorRaisingArgumentParser()
2383 raises = self.assertRaises
2384 raises(TypeError, parser.add_mutually_exclusive_group, title='foo')
2385
2386 def test_invalid_add_argument(self):
2387 parser = ErrorRaisingArgumentParser()
2388 group = parser.add_mutually_exclusive_group()
2389 add_argument = group.add_argument
2390 raises = self.assertRaises
2391 raises(ValueError, add_argument, '--foo', required=True)
2392 raises(ValueError, add_argument, 'bar')
2393 raises(ValueError, add_argument, 'bar', nargs='+')
2394 raises(ValueError, add_argument, 'bar', nargs=1)
2395 raises(ValueError, add_argument, 'bar', nargs=argparse.PARSER)
2396
Steven Bethard49998ee2010-11-01 16:29:26 +00002397 def test_help(self):
2398 parser = ErrorRaisingArgumentParser(prog='PROG')
2399 group1 = parser.add_mutually_exclusive_group()
2400 group1.add_argument('--foo', action='store_true')
2401 group1.add_argument('--bar', action='store_false')
2402 group2 = parser.add_mutually_exclusive_group()
2403 group2.add_argument('--soup', action='store_true')
2404 group2.add_argument('--nuts', action='store_false')
2405 expected = '''\
2406 usage: PROG [-h] [--foo | --bar] [--soup | --nuts]
2407
2408 optional arguments:
2409 -h, --help show this help message and exit
2410 --foo
2411 --bar
2412 --soup
2413 --nuts
2414 '''
2415 self.assertEqual(parser.format_help(), textwrap.dedent(expected))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002416
2417class MEMixin(object):
2418
2419 def test_failures_when_not_required(self):
2420 parse_args = self.get_parser(required=False).parse_args
2421 error = ArgumentParserError
2422 for args_string in self.failures:
2423 self.assertRaises(error, parse_args, args_string.split())
2424
2425 def test_failures_when_required(self):
2426 parse_args = self.get_parser(required=True).parse_args
2427 error = ArgumentParserError
2428 for args_string in self.failures + ['']:
2429 self.assertRaises(error, parse_args, args_string.split())
2430
2431 def test_successes_when_not_required(self):
2432 parse_args = self.get_parser(required=False).parse_args
2433 successes = self.successes + self.successes_when_not_required
2434 for args_string, expected_ns in successes:
2435 actual_ns = parse_args(args_string.split())
2436 self.assertEqual(actual_ns, expected_ns)
2437
2438 def test_successes_when_required(self):
2439 parse_args = self.get_parser(required=True).parse_args
2440 for args_string, expected_ns in self.successes:
2441 actual_ns = parse_args(args_string.split())
2442 self.assertEqual(actual_ns, expected_ns)
2443
2444 def test_usage_when_not_required(self):
2445 format_usage = self.get_parser(required=False).format_usage
2446 expected_usage = self.usage_when_not_required
2447 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2448
2449 def test_usage_when_required(self):
2450 format_usage = self.get_parser(required=True).format_usage
2451 expected_usage = self.usage_when_required
2452 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2453
2454 def test_help_when_not_required(self):
2455 format_help = self.get_parser(required=False).format_help
2456 help = self.usage_when_not_required + self.help
2457 self.assertEqual(format_help(), textwrap.dedent(help))
2458
2459 def test_help_when_required(self):
2460 format_help = self.get_parser(required=True).format_help
2461 help = self.usage_when_required + self.help
2462 self.assertEqual(format_help(), textwrap.dedent(help))
2463
2464
2465class TestMutuallyExclusiveSimple(MEMixin, TestCase):
2466
2467 def get_parser(self, required=None):
2468 parser = ErrorRaisingArgumentParser(prog='PROG')
2469 group = parser.add_mutually_exclusive_group(required=required)
2470 group.add_argument('--bar', help='bar help')
2471 group.add_argument('--baz', nargs='?', const='Z', help='baz help')
2472 return parser
2473
2474 failures = ['--bar X --baz Y', '--bar X --baz']
2475 successes = [
2476 ('--bar X', NS(bar='X', baz=None)),
2477 ('--bar X --bar Z', NS(bar='Z', baz=None)),
2478 ('--baz Y', NS(bar=None, baz='Y')),
2479 ('--baz', NS(bar=None, baz='Z')),
2480 ]
2481 successes_when_not_required = [
2482 ('', NS(bar=None, baz=None)),
2483 ]
2484
2485 usage_when_not_required = '''\
2486 usage: PROG [-h] [--bar BAR | --baz [BAZ]]
2487 '''
2488 usage_when_required = '''\
2489 usage: PROG [-h] (--bar BAR | --baz [BAZ])
2490 '''
2491 help = '''\
2492
2493 optional arguments:
2494 -h, --help show this help message and exit
2495 --bar BAR bar help
2496 --baz [BAZ] baz help
2497 '''
2498
2499
2500class TestMutuallyExclusiveLong(MEMixin, TestCase):
2501
2502 def get_parser(self, required=None):
2503 parser = ErrorRaisingArgumentParser(prog='PROG')
2504 parser.add_argument('--abcde', help='abcde help')
2505 parser.add_argument('--fghij', help='fghij help')
2506 group = parser.add_mutually_exclusive_group(required=required)
2507 group.add_argument('--klmno', help='klmno help')
2508 group.add_argument('--pqrst', help='pqrst help')
2509 return parser
2510
2511 failures = ['--klmno X --pqrst Y']
2512 successes = [
2513 ('--klmno X', NS(abcde=None, fghij=None, klmno='X', pqrst=None)),
2514 ('--abcde Y --klmno X',
2515 NS(abcde='Y', fghij=None, klmno='X', pqrst=None)),
2516 ('--pqrst X', NS(abcde=None, fghij=None, klmno=None, pqrst='X')),
2517 ('--pqrst X --fghij Y',
2518 NS(abcde=None, fghij='Y', klmno=None, pqrst='X')),
2519 ]
2520 successes_when_not_required = [
2521 ('', NS(abcde=None, fghij=None, klmno=None, pqrst=None)),
2522 ]
2523
2524 usage_when_not_required = '''\
2525 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2526 [--klmno KLMNO | --pqrst PQRST]
2527 '''
2528 usage_when_required = '''\
2529 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2530 (--klmno KLMNO | --pqrst PQRST)
2531 '''
2532 help = '''\
2533
2534 optional arguments:
2535 -h, --help show this help message and exit
2536 --abcde ABCDE abcde help
2537 --fghij FGHIJ fghij help
2538 --klmno KLMNO klmno help
2539 --pqrst PQRST pqrst help
2540 '''
2541
2542
2543class TestMutuallyExclusiveFirstSuppressed(MEMixin, TestCase):
2544
2545 def get_parser(self, required):
2546 parser = ErrorRaisingArgumentParser(prog='PROG')
2547 group = parser.add_mutually_exclusive_group(required=required)
2548 group.add_argument('-x', help=argparse.SUPPRESS)
2549 group.add_argument('-y', action='store_false', help='y help')
2550 return parser
2551
2552 failures = ['-x X -y']
2553 successes = [
2554 ('-x X', NS(x='X', y=True)),
2555 ('-x X -x Y', NS(x='Y', y=True)),
2556 ('-y', NS(x=None, y=False)),
2557 ]
2558 successes_when_not_required = [
2559 ('', NS(x=None, y=True)),
2560 ]
2561
2562 usage_when_not_required = '''\
2563 usage: PROG [-h] [-y]
2564 '''
2565 usage_when_required = '''\
2566 usage: PROG [-h] -y
2567 '''
2568 help = '''\
2569
2570 optional arguments:
2571 -h, --help show this help message and exit
2572 -y y help
2573 '''
2574
2575
2576class TestMutuallyExclusiveManySuppressed(MEMixin, TestCase):
2577
2578 def get_parser(self, required):
2579 parser = ErrorRaisingArgumentParser(prog='PROG')
2580 group = parser.add_mutually_exclusive_group(required=required)
2581 add = group.add_argument
2582 add('--spam', action='store_true', help=argparse.SUPPRESS)
2583 add('--badger', action='store_false', help=argparse.SUPPRESS)
2584 add('--bladder', help=argparse.SUPPRESS)
2585 return parser
2586
2587 failures = [
2588 '--spam --badger',
2589 '--badger --bladder B',
2590 '--bladder B --spam',
2591 ]
2592 successes = [
2593 ('--spam', NS(spam=True, badger=True, bladder=None)),
2594 ('--badger', NS(spam=False, badger=False, bladder=None)),
2595 ('--bladder B', NS(spam=False, badger=True, bladder='B')),
2596 ('--spam --spam', NS(spam=True, badger=True, bladder=None)),
2597 ]
2598 successes_when_not_required = [
2599 ('', NS(spam=False, badger=True, bladder=None)),
2600 ]
2601
2602 usage_when_required = usage_when_not_required = '''\
2603 usage: PROG [-h]
2604 '''
2605 help = '''\
2606
2607 optional arguments:
2608 -h, --help show this help message and exit
2609 '''
2610
2611
2612class TestMutuallyExclusiveOptionalAndPositional(MEMixin, TestCase):
2613
2614 def get_parser(self, required):
2615 parser = ErrorRaisingArgumentParser(prog='PROG')
2616 group = parser.add_mutually_exclusive_group(required=required)
2617 group.add_argument('--foo', action='store_true', help='FOO')
2618 group.add_argument('--spam', help='SPAM')
2619 group.add_argument('badger', nargs='*', default='X', help='BADGER')
2620 return parser
2621
2622 failures = [
2623 '--foo --spam S',
2624 '--spam S X',
2625 'X --foo',
2626 'X Y Z --spam S',
2627 '--foo X Y',
2628 ]
2629 successes = [
2630 ('--foo', NS(foo=True, spam=None, badger='X')),
2631 ('--spam S', NS(foo=False, spam='S', badger='X')),
2632 ('X', NS(foo=False, spam=None, badger=['X'])),
2633 ('X Y Z', NS(foo=False, spam=None, badger=['X', 'Y', 'Z'])),
2634 ]
2635 successes_when_not_required = [
2636 ('', NS(foo=False, spam=None, badger='X')),
2637 ]
2638
2639 usage_when_not_required = '''\
2640 usage: PROG [-h] [--foo | --spam SPAM | badger [badger ...]]
2641 '''
2642 usage_when_required = '''\
2643 usage: PROG [-h] (--foo | --spam SPAM | badger [badger ...])
2644 '''
2645 help = '''\
2646
2647 positional arguments:
2648 badger BADGER
2649
2650 optional arguments:
2651 -h, --help show this help message and exit
2652 --foo FOO
2653 --spam SPAM SPAM
2654 '''
2655
2656
2657class TestMutuallyExclusiveOptionalsMixed(MEMixin, TestCase):
2658
2659 def get_parser(self, required):
2660 parser = ErrorRaisingArgumentParser(prog='PROG')
2661 parser.add_argument('-x', action='store_true', help='x help')
2662 group = parser.add_mutually_exclusive_group(required=required)
2663 group.add_argument('-a', action='store_true', help='a help')
2664 group.add_argument('-b', action='store_true', help='b help')
2665 parser.add_argument('-y', action='store_true', help='y help')
2666 group.add_argument('-c', action='store_true', help='c help')
2667 return parser
2668
2669 failures = ['-a -b', '-b -c', '-a -c', '-a -b -c']
2670 successes = [
2671 ('-a', NS(a=True, b=False, c=False, x=False, y=False)),
2672 ('-b', NS(a=False, b=True, c=False, x=False, y=False)),
2673 ('-c', NS(a=False, b=False, c=True, x=False, y=False)),
2674 ('-a -x', NS(a=True, b=False, c=False, x=True, y=False)),
2675 ('-y -b', NS(a=False, b=True, c=False, x=False, y=True)),
2676 ('-x -y -c', NS(a=False, b=False, c=True, x=True, y=True)),
2677 ]
2678 successes_when_not_required = [
2679 ('', NS(a=False, b=False, c=False, x=False, y=False)),
2680 ('-x', NS(a=False, b=False, c=False, x=True, y=False)),
2681 ('-y', NS(a=False, b=False, c=False, x=False, y=True)),
2682 ]
2683
2684 usage_when_required = usage_when_not_required = '''\
2685 usage: PROG [-h] [-x] [-a] [-b] [-y] [-c]
2686 '''
2687 help = '''\
2688
2689 optional arguments:
2690 -h, --help show this help message and exit
2691 -x x help
2692 -a a help
2693 -b b help
2694 -y y help
2695 -c c help
2696 '''
2697
2698
Georg Brandl0f6b47a2011-01-30 12:19:35 +00002699class TestMutuallyExclusiveInGroup(MEMixin, TestCase):
2700
2701 def get_parser(self, required=None):
2702 parser = ErrorRaisingArgumentParser(prog='PROG')
2703 titled_group = parser.add_argument_group(
2704 title='Titled group', description='Group description')
2705 mutex_group = \
2706 titled_group.add_mutually_exclusive_group(required=required)
2707 mutex_group.add_argument('--bar', help='bar help')
2708 mutex_group.add_argument('--baz', help='baz help')
2709 return parser
2710
2711 failures = ['--bar X --baz Y', '--baz X --bar Y']
2712 successes = [
2713 ('--bar X', NS(bar='X', baz=None)),
2714 ('--baz Y', NS(bar=None, baz='Y')),
2715 ]
2716 successes_when_not_required = [
2717 ('', NS(bar=None, baz=None)),
2718 ]
2719
2720 usage_when_not_required = '''\
2721 usage: PROG [-h] [--bar BAR | --baz BAZ]
2722 '''
2723 usage_when_required = '''\
2724 usage: PROG [-h] (--bar BAR | --baz BAZ)
2725 '''
2726 help = '''\
2727
2728 optional arguments:
2729 -h, --help show this help message and exit
2730
2731 Titled group:
2732 Group description
2733
2734 --bar BAR bar help
2735 --baz BAZ baz help
2736 '''
2737
2738
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002739class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase):
2740
2741 def get_parser(self, required):
2742 parser = ErrorRaisingArgumentParser(prog='PROG')
2743 parser.add_argument('x', help='x help')
2744 parser.add_argument('-y', action='store_true', help='y help')
2745 group = parser.add_mutually_exclusive_group(required=required)
2746 group.add_argument('a', nargs='?', help='a help')
2747 group.add_argument('-b', action='store_true', help='b help')
2748 group.add_argument('-c', action='store_true', help='c help')
2749 return parser
2750
2751 failures = ['X A -b', '-b -c', '-c X A']
2752 successes = [
2753 ('X A', NS(a='A', b=False, c=False, x='X', y=False)),
2754 ('X -b', NS(a=None, b=True, c=False, x='X', y=False)),
2755 ('X -c', NS(a=None, b=False, c=True, x='X', y=False)),
2756 ('X A -y', NS(a='A', b=False, c=False, x='X', y=True)),
2757 ('X -y -b', NS(a=None, b=True, c=False, x='X', y=True)),
2758 ]
2759 successes_when_not_required = [
2760 ('X', NS(a=None, b=False, c=False, x='X', y=False)),
2761 ('X -y', NS(a=None, b=False, c=False, x='X', y=True)),
2762 ]
2763
2764 usage_when_required = usage_when_not_required = '''\
2765 usage: PROG [-h] [-y] [-b] [-c] x [a]
2766 '''
2767 help = '''\
2768
2769 positional arguments:
2770 x x help
2771 a a help
2772
2773 optional arguments:
2774 -h, --help show this help message and exit
2775 -y y help
2776 -b b help
2777 -c c help
2778 '''
2779
2780# =================================================
2781# Mutually exclusive group in parent parser tests
2782# =================================================
2783
2784class MEPBase(object):
2785
2786 def get_parser(self, required=None):
2787 parent = super(MEPBase, self).get_parser(required=required)
2788 parser = ErrorRaisingArgumentParser(
2789 prog=parent.prog, add_help=False, parents=[parent])
2790 return parser
2791
2792
2793class TestMutuallyExclusiveGroupErrorsParent(
2794 MEPBase, TestMutuallyExclusiveGroupErrors):
2795 pass
2796
2797
2798class TestMutuallyExclusiveSimpleParent(
2799 MEPBase, TestMutuallyExclusiveSimple):
2800 pass
2801
2802
2803class TestMutuallyExclusiveLongParent(
2804 MEPBase, TestMutuallyExclusiveLong):
2805 pass
2806
2807
2808class TestMutuallyExclusiveFirstSuppressedParent(
2809 MEPBase, TestMutuallyExclusiveFirstSuppressed):
2810 pass
2811
2812
2813class TestMutuallyExclusiveManySuppressedParent(
2814 MEPBase, TestMutuallyExclusiveManySuppressed):
2815 pass
2816
2817
2818class TestMutuallyExclusiveOptionalAndPositionalParent(
2819 MEPBase, TestMutuallyExclusiveOptionalAndPositional):
2820 pass
2821
2822
2823class TestMutuallyExclusiveOptionalsMixedParent(
2824 MEPBase, TestMutuallyExclusiveOptionalsMixed):
2825 pass
2826
2827
2828class TestMutuallyExclusiveOptionalsAndPositionalsMixedParent(
2829 MEPBase, TestMutuallyExclusiveOptionalsAndPositionalsMixed):
2830 pass
2831
2832# =================
2833# Set default tests
2834# =================
2835
2836class TestSetDefaults(TestCase):
2837
2838 def test_set_defaults_no_args(self):
2839 parser = ErrorRaisingArgumentParser()
2840 parser.set_defaults(x='foo')
2841 parser.set_defaults(y='bar', z=1)
2842 self.assertEqual(NS(x='foo', y='bar', z=1),
2843 parser.parse_args([]))
2844 self.assertEqual(NS(x='foo', y='bar', z=1),
2845 parser.parse_args([], NS()))
2846 self.assertEqual(NS(x='baz', y='bar', z=1),
2847 parser.parse_args([], NS(x='baz')))
2848 self.assertEqual(NS(x='baz', y='bar', z=2),
2849 parser.parse_args([], NS(x='baz', z=2)))
2850
2851 def test_set_defaults_with_args(self):
2852 parser = ErrorRaisingArgumentParser()
2853 parser.set_defaults(x='foo', y='bar')
2854 parser.add_argument('-x', default='xfoox')
2855 self.assertEqual(NS(x='xfoox', y='bar'),
2856 parser.parse_args([]))
2857 self.assertEqual(NS(x='xfoox', y='bar'),
2858 parser.parse_args([], NS()))
2859 self.assertEqual(NS(x='baz', y='bar'),
2860 parser.parse_args([], NS(x='baz')))
2861 self.assertEqual(NS(x='1', y='bar'),
2862 parser.parse_args('-x 1'.split()))
2863 self.assertEqual(NS(x='1', y='bar'),
2864 parser.parse_args('-x 1'.split(), NS()))
2865 self.assertEqual(NS(x='1', y='bar'),
2866 parser.parse_args('-x 1'.split(), NS(x='baz')))
2867
2868 def test_set_defaults_subparsers(self):
2869 parser = ErrorRaisingArgumentParser()
2870 parser.set_defaults(x='foo')
2871 subparsers = parser.add_subparsers()
2872 parser_a = subparsers.add_parser('a')
2873 parser_a.set_defaults(y='bar')
2874 self.assertEqual(NS(x='foo', y='bar'),
2875 parser.parse_args('a'.split()))
2876
2877 def test_set_defaults_parents(self):
2878 parent = ErrorRaisingArgumentParser(add_help=False)
2879 parent.set_defaults(x='foo')
2880 parser = ErrorRaisingArgumentParser(parents=[parent])
2881 self.assertEqual(NS(x='foo'), parser.parse_args([]))
2882
R David Murray7570cbd2014-10-17 19:55:11 -04002883 def test_set_defaults_on_parent_and_subparser(self):
2884 parser = argparse.ArgumentParser()
2885 xparser = parser.add_subparsers().add_parser('X')
2886 parser.set_defaults(foo=1)
2887 xparser.set_defaults(foo=2)
2888 self.assertEqual(NS(foo=2), parser.parse_args(['X']))
2889
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002890 def test_set_defaults_same_as_add_argument(self):
2891 parser = ErrorRaisingArgumentParser()
2892 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2893 parser.add_argument('-w')
2894 parser.add_argument('-x', default='XX')
2895 parser.add_argument('y', nargs='?')
2896 parser.add_argument('z', nargs='?', default='ZZ')
2897
2898 # defaults set previously
2899 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2900 parser.parse_args([]))
2901
2902 # reset defaults
2903 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2904 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2905 parser.parse_args([]))
2906
2907 def test_set_defaults_same_as_add_argument_group(self):
2908 parser = ErrorRaisingArgumentParser()
2909 parser.set_defaults(w='W', x='X', y='Y', z='Z')
2910 group = parser.add_argument_group('foo')
2911 group.add_argument('-w')
2912 group.add_argument('-x', default='XX')
2913 group.add_argument('y', nargs='?')
2914 group.add_argument('z', nargs='?', default='ZZ')
2915
2916
2917 # defaults set previously
2918 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
2919 parser.parse_args([]))
2920
2921 # reset defaults
2922 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
2923 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
2924 parser.parse_args([]))
2925
2926# =================
2927# Get default tests
2928# =================
2929
2930class TestGetDefault(TestCase):
2931
2932 def test_get_default(self):
2933 parser = ErrorRaisingArgumentParser()
Berker Peksag1c5f56a2014-07-06 09:33:20 +03002934 self.assertIsNone(parser.get_default("foo"))
2935 self.assertIsNone(parser.get_default("bar"))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002936
2937 parser.add_argument("--foo")
Berker Peksag1c5f56a2014-07-06 09:33:20 +03002938 self.assertIsNone(parser.get_default("foo"))
2939 self.assertIsNone(parser.get_default("bar"))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002940
2941 parser.add_argument("--bar", type=int, default=42)
Berker Peksag1c5f56a2014-07-06 09:33:20 +03002942 self.assertIsNone(parser.get_default("foo"))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002943 self.assertEqual(42, parser.get_default("bar"))
2944
2945 parser.set_defaults(foo="badger")
2946 self.assertEqual("badger", parser.get_default("foo"))
2947 self.assertEqual(42, parser.get_default("bar"))
2948
2949# ==========================
2950# Namespace 'contains' tests
2951# ==========================
2952
2953class TestNamespaceContainsSimple(TestCase):
2954
2955 def test_empty(self):
2956 ns = argparse.Namespace()
Berker Peksag1c5f56a2014-07-06 09:33:20 +03002957 self.assertNotIn('', ns)
2958 self.assertNotIn('x', ns)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002959
2960 def test_non_empty(self):
2961 ns = argparse.Namespace(x=1, y=2)
Berker Peksag1c5f56a2014-07-06 09:33:20 +03002962 self.assertNotIn('', ns)
2963 self.assertIn('x', ns)
2964 self.assertIn('y', ns)
2965 self.assertNotIn('xx', ns)
2966 self.assertNotIn('z', ns)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002967
2968# =====================
2969# Help formatting tests
2970# =====================
2971
2972class TestHelpFormattingMetaclass(type):
2973
2974 def __init__(cls, name, bases, bodydict):
2975 if name == 'HelpTestCase':
2976 return
2977
2978 class AddTests(object):
2979
2980 def __init__(self, test_class, func_suffix, std_name):
2981 self.func_suffix = func_suffix
2982 self.std_name = std_name
2983
2984 for test_func in [self.test_format,
2985 self.test_print,
2986 self.test_print_file]:
2987 test_name = '%s_%s' % (test_func.__name__, func_suffix)
2988
2989 def test_wrapper(self, test_func=test_func):
2990 test_func(self)
2991 try:
2992 test_wrapper.__name__ = test_name
2993 except TypeError:
2994 pass
2995 setattr(test_class, test_name, test_wrapper)
2996
2997 def _get_parser(self, tester):
2998 parser = argparse.ArgumentParser(
2999 *tester.parser_signature.args,
3000 **tester.parser_signature.kwargs)
Steven Bethard8a6a1982011-03-27 13:53:53 +02003001 for argument_sig in getattr(tester, 'argument_signatures', []):
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003002 parser.add_argument(*argument_sig.args,
3003 **argument_sig.kwargs)
Steven Bethard8a6a1982011-03-27 13:53:53 +02003004 group_sigs = getattr(tester, 'argument_group_signatures', [])
3005 for group_sig, argument_sigs in group_sigs:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003006 group = parser.add_argument_group(*group_sig.args,
3007 **group_sig.kwargs)
3008 for argument_sig in argument_sigs:
3009 group.add_argument(*argument_sig.args,
3010 **argument_sig.kwargs)
Steven Bethard8a6a1982011-03-27 13:53:53 +02003011 subparsers_sigs = getattr(tester, 'subparsers_signatures', [])
3012 if subparsers_sigs:
3013 subparsers = parser.add_subparsers()
3014 for subparser_sig in subparsers_sigs:
3015 subparsers.add_parser(*subparser_sig.args,
3016 **subparser_sig.kwargs)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003017 return parser
3018
3019 def _test(self, tester, parser_text):
3020 expected_text = getattr(tester, self.func_suffix)
3021 expected_text = textwrap.dedent(expected_text)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003022 tester.assertEqual(expected_text, parser_text)
3023
3024 def test_format(self, tester):
3025 parser = self._get_parser(tester)
3026 format = getattr(parser, 'format_%s' % self.func_suffix)
3027 self._test(tester, format())
3028
3029 def test_print(self, tester):
3030 parser = self._get_parser(tester)
3031 print_ = getattr(parser, 'print_%s' % self.func_suffix)
3032 old_stream = getattr(sys, self.std_name)
Benjamin Petersonb48af542010-04-11 20:43:16 +00003033 setattr(sys, self.std_name, StdIOBuffer())
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003034 try:
3035 print_()
3036 parser_text = getattr(sys, self.std_name).getvalue()
3037 finally:
3038 setattr(sys, self.std_name, old_stream)
3039 self._test(tester, parser_text)
3040
3041 def test_print_file(self, tester):
3042 parser = self._get_parser(tester)
3043 print_ = getattr(parser, 'print_%s' % self.func_suffix)
Benjamin Petersonb48af542010-04-11 20:43:16 +00003044 sfile = StdIOBuffer()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003045 print_(sfile)
3046 parser_text = sfile.getvalue()
3047 self._test(tester, parser_text)
3048
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003049 # add tests for {format,print}_{usage,help}
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003050 for func_suffix, std_name in [('usage', 'stdout'),
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003051 ('help', 'stdout')]:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003052 AddTests(cls, func_suffix, std_name)
3053
3054bases = TestCase,
3055HelpTestCase = TestHelpFormattingMetaclass('HelpTestCase', bases, {})
3056
3057
3058class TestHelpBiggerOptionals(HelpTestCase):
3059 """Make sure that argument help aligns when options are longer"""
3060
3061 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003062 epilog='EPILOG')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003063 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003064 Sig('-v', '--version', action='version', version='0.1'),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003065 Sig('-x', action='store_true', help='X HELP'),
3066 Sig('--y', help='Y HELP'),
3067 Sig('foo', help='FOO HELP'),
3068 Sig('bar', help='BAR HELP'),
3069 ]
3070 argument_group_signatures = []
3071 usage = '''\
3072 usage: PROG [-h] [-v] [-x] [--y Y] foo bar
3073 '''
3074 help = usage + '''\
3075
3076 DESCRIPTION
3077
3078 positional arguments:
3079 foo FOO HELP
3080 bar BAR HELP
3081
3082 optional arguments:
3083 -h, --help show this help message and exit
3084 -v, --version show program's version number and exit
3085 -x X HELP
3086 --y Y Y HELP
3087
3088 EPILOG
3089 '''
3090 version = '''\
3091 0.1
3092 '''
3093
Serhiy Storchakaf4511122014-01-09 23:14:27 +02003094class TestShortColumns(HelpTestCase):
3095 '''Test extremely small number of columns.
3096
3097 TestCase prevents "COLUMNS" from being too small in the tests themselves,
Martin Panter2e4571a2015-11-14 01:07:43 +00003098 but we don't want any exceptions thrown in such cases. Only ugly representation.
Serhiy Storchakaf4511122014-01-09 23:14:27 +02003099 '''
3100 def setUp(self):
3101 env = support.EnvironmentVarGuard()
3102 env.set("COLUMNS", '15')
3103 self.addCleanup(env.__exit__)
3104
3105 parser_signature = TestHelpBiggerOptionals.parser_signature
3106 argument_signatures = TestHelpBiggerOptionals.argument_signatures
3107 argument_group_signatures = TestHelpBiggerOptionals.argument_group_signatures
3108 usage = '''\
3109 usage: PROG
3110 [-h]
3111 [-v]
3112 [-x]
3113 [--y Y]
3114 foo
3115 bar
3116 '''
3117 help = usage + '''\
3118
3119 DESCRIPTION
3120
3121 positional arguments:
3122 foo
3123 FOO HELP
3124 bar
3125 BAR HELP
3126
3127 optional arguments:
3128 -h, --help
3129 show this
3130 help
3131 message and
3132 exit
3133 -v, --version
3134 show
3135 program's
3136 version
3137 number and
3138 exit
3139 -x
3140 X HELP
3141 --y Y
3142 Y HELP
3143
3144 EPILOG
3145 '''
3146 version = TestHelpBiggerOptionals.version
3147
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003148
3149class TestHelpBiggerOptionalGroups(HelpTestCase):
3150 """Make sure that argument help aligns when options are longer"""
3151
3152 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003153 epilog='EPILOG')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003154 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003155 Sig('-v', '--version', action='version', version='0.1'),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003156 Sig('-x', action='store_true', help='X HELP'),
3157 Sig('--y', help='Y HELP'),
3158 Sig('foo', help='FOO HELP'),
3159 Sig('bar', help='BAR HELP'),
3160 ]
3161 argument_group_signatures = [
3162 (Sig('GROUP TITLE', description='GROUP DESCRIPTION'), [
3163 Sig('baz', help='BAZ HELP'),
3164 Sig('-z', nargs='+', help='Z HELP')]),
3165 ]
3166 usage = '''\
3167 usage: PROG [-h] [-v] [-x] [--y Y] [-z Z [Z ...]] foo bar baz
3168 '''
3169 help = usage + '''\
3170
3171 DESCRIPTION
3172
3173 positional arguments:
3174 foo FOO HELP
3175 bar BAR HELP
3176
3177 optional arguments:
3178 -h, --help show this help message and exit
3179 -v, --version show program's version number and exit
3180 -x X HELP
3181 --y Y Y HELP
3182
3183 GROUP TITLE:
3184 GROUP DESCRIPTION
3185
3186 baz BAZ HELP
3187 -z Z [Z ...] Z HELP
3188
3189 EPILOG
3190 '''
3191 version = '''\
3192 0.1
3193 '''
3194
3195
3196class TestHelpBiggerPositionals(HelpTestCase):
3197 """Make sure that help aligns when arguments are longer"""
3198
3199 parser_signature = Sig(usage='USAGE', description='DESCRIPTION')
3200 argument_signatures = [
3201 Sig('-x', action='store_true', help='X HELP'),
3202 Sig('--y', help='Y HELP'),
3203 Sig('ekiekiekifekang', help='EKI HELP'),
3204 Sig('bar', help='BAR HELP'),
3205 ]
3206 argument_group_signatures = []
3207 usage = '''\
3208 usage: USAGE
3209 '''
3210 help = usage + '''\
3211
3212 DESCRIPTION
3213
3214 positional arguments:
3215 ekiekiekifekang EKI HELP
3216 bar BAR HELP
3217
3218 optional arguments:
3219 -h, --help show this help message and exit
3220 -x X HELP
3221 --y Y Y HELP
3222 '''
3223
3224 version = ''
3225
3226
3227class TestHelpReformatting(HelpTestCase):
3228 """Make sure that text after short names starts on the first line"""
3229
3230 parser_signature = Sig(
3231 prog='PROG',
3232 description=' oddly formatted\n'
3233 'description\n'
3234 '\n'
3235 'that is so long that it should go onto multiple '
3236 'lines when wrapped')
3237 argument_signatures = [
3238 Sig('-x', metavar='XX', help='oddly\n'
3239 ' formatted -x help'),
3240 Sig('y', metavar='yyy', help='normal y help'),
3241 ]
3242 argument_group_signatures = [
3243 (Sig('title', description='\n'
3244 ' oddly formatted group\n'
3245 '\n'
3246 'description'),
3247 [Sig('-a', action='store_true',
3248 help=' oddly \n'
3249 'formatted -a help \n'
3250 ' again, so long that it should be wrapped over '
3251 'multiple lines')]),
3252 ]
3253 usage = '''\
3254 usage: PROG [-h] [-x XX] [-a] yyy
3255 '''
3256 help = usage + '''\
3257
3258 oddly formatted description that is so long that it should go onto \
3259multiple
3260 lines when wrapped
3261
3262 positional arguments:
3263 yyy normal y help
3264
3265 optional arguments:
3266 -h, --help show this help message and exit
3267 -x XX oddly formatted -x help
3268
3269 title:
3270 oddly formatted group description
3271
3272 -a oddly formatted -a help again, so long that it should \
3273be wrapped
3274 over multiple lines
3275 '''
3276 version = ''
3277
3278
3279class TestHelpWrappingShortNames(HelpTestCase):
3280 """Make sure that text after short names starts on the first line"""
3281
3282 parser_signature = Sig(prog='PROG', description= 'D\nD' * 30)
3283 argument_signatures = [
3284 Sig('-x', metavar='XX', help='XHH HX' * 20),
3285 Sig('y', metavar='yyy', help='YH YH' * 20),
3286 ]
3287 argument_group_signatures = [
3288 (Sig('ALPHAS'), [
3289 Sig('-a', action='store_true', help='AHHH HHA' * 10)]),
3290 ]
3291 usage = '''\
3292 usage: PROG [-h] [-x XX] [-a] yyy
3293 '''
3294 help = usage + '''\
3295
3296 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3297DD DD DD
3298 DD DD DD DD D
3299
3300 positional arguments:
3301 yyy YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3302YHYH YHYH
3303 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3304
3305 optional arguments:
3306 -h, --help show this help message and exit
3307 -x XX XHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH \
3308HXXHH HXXHH
3309 HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HX
3310
3311 ALPHAS:
3312 -a AHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH \
3313HHAAHHH
3314 HHAAHHH HHAAHHH HHA
3315 '''
3316 version = ''
3317
3318
3319class TestHelpWrappingLongNames(HelpTestCase):
3320 """Make sure that text after long names starts on the next line"""
3321
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003322 parser_signature = Sig(usage='USAGE', description= 'D D' * 30)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003323 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003324 Sig('-v', '--version', action='version', version='V V' * 30),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003325 Sig('-x', metavar='X' * 25, help='XH XH' * 20),
3326 Sig('y', metavar='y' * 25, help='YH YH' * 20),
3327 ]
3328 argument_group_signatures = [
3329 (Sig('ALPHAS'), [
3330 Sig('-a', metavar='A' * 25, help='AH AH' * 20),
3331 Sig('z', metavar='z' * 25, help='ZH ZH' * 20)]),
3332 ]
3333 usage = '''\
3334 usage: USAGE
3335 '''
3336 help = usage + '''\
3337
3338 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3339DD DD DD
3340 DD DD DD DD D
3341
3342 positional arguments:
3343 yyyyyyyyyyyyyyyyyyyyyyyyy
3344 YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3345YHYH YHYH
3346 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3347
3348 optional arguments:
3349 -h, --help show this help message and exit
3350 -v, --version show program's version number and exit
3351 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3352 XH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH \
3353XHXH XHXH
3354 XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XH
3355
3356 ALPHAS:
3357 -a AAAAAAAAAAAAAAAAAAAAAAAAA
3358 AH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH \
3359AHAH AHAH
3360 AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AH
3361 zzzzzzzzzzzzzzzzzzzzzzzzz
3362 ZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH \
3363ZHZH ZHZH
3364 ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZH
3365 '''
3366 version = '''\
3367 V VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV \
3368VV VV VV
3369 VV VV VV VV V
3370 '''
3371
3372
3373class TestHelpUsage(HelpTestCase):
3374 """Test basic usage messages"""
3375
3376 parser_signature = Sig(prog='PROG')
3377 argument_signatures = [
3378 Sig('-w', nargs='+', help='w'),
3379 Sig('-x', nargs='*', help='x'),
3380 Sig('a', help='a'),
3381 Sig('b', help='b', nargs=2),
3382 Sig('c', help='c', nargs='?'),
3383 ]
3384 argument_group_signatures = [
3385 (Sig('group'), [
3386 Sig('-y', nargs='?', help='y'),
3387 Sig('-z', nargs=3, help='z'),
3388 Sig('d', help='d', nargs='*'),
3389 Sig('e', help='e', nargs='+'),
3390 ])
3391 ]
3392 usage = '''\
3393 usage: PROG [-h] [-w W [W ...]] [-x [X [X ...]]] [-y [Y]] [-z Z Z Z]
3394 a b b [c] [d [d ...]] e [e ...]
3395 '''
3396 help = usage + '''\
3397
3398 positional arguments:
3399 a a
3400 b b
3401 c c
3402
3403 optional arguments:
3404 -h, --help show this help message and exit
3405 -w W [W ...] w
3406 -x [X [X ...]] x
3407
3408 group:
3409 -y [Y] y
3410 -z Z Z Z z
3411 d d
3412 e e
3413 '''
3414 version = ''
3415
3416
3417class TestHelpOnlyUserGroups(HelpTestCase):
3418 """Test basic usage messages"""
3419
3420 parser_signature = Sig(prog='PROG', add_help=False)
3421 argument_signatures = []
3422 argument_group_signatures = [
3423 (Sig('xxxx'), [
3424 Sig('-x', help='x'),
3425 Sig('a', help='a'),
3426 ]),
3427 (Sig('yyyy'), [
3428 Sig('b', help='b'),
3429 Sig('-y', help='y'),
3430 ]),
3431 ]
3432 usage = '''\
3433 usage: PROG [-x X] [-y Y] a b
3434 '''
3435 help = usage + '''\
3436
3437 xxxx:
3438 -x X x
3439 a a
3440
3441 yyyy:
3442 b b
3443 -y Y y
3444 '''
3445 version = ''
3446
3447
3448class TestHelpUsageLongProg(HelpTestCase):
3449 """Test usage messages where the prog is long"""
3450
3451 parser_signature = Sig(prog='P' * 60)
3452 argument_signatures = [
3453 Sig('-w', metavar='W'),
3454 Sig('-x', metavar='X'),
3455 Sig('a'),
3456 Sig('b'),
3457 ]
3458 argument_group_signatures = []
3459 usage = '''\
3460 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3461 [-h] [-w W] [-x X] a b
3462 '''
3463 help = usage + '''\
3464
3465 positional arguments:
3466 a
3467 b
3468
3469 optional arguments:
3470 -h, --help show this help message and exit
3471 -w W
3472 -x X
3473 '''
3474 version = ''
3475
3476
3477class TestHelpUsageLongProgOptionsWrap(HelpTestCase):
3478 """Test usage messages where the prog is long and the optionals wrap"""
3479
3480 parser_signature = Sig(prog='P' * 60)
3481 argument_signatures = [
3482 Sig('-w', metavar='W' * 25),
3483 Sig('-x', metavar='X' * 25),
3484 Sig('-y', metavar='Y' * 25),
3485 Sig('-z', metavar='Z' * 25),
3486 Sig('a'),
3487 Sig('b'),
3488 ]
3489 argument_group_signatures = []
3490 usage = '''\
3491 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3492 [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3493[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3494 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3495 a b
3496 '''
3497 help = usage + '''\
3498
3499 positional arguments:
3500 a
3501 b
3502
3503 optional arguments:
3504 -h, --help show this help message and exit
3505 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3506 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3507 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3508 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3509 '''
3510 version = ''
3511
3512
3513class TestHelpUsageLongProgPositionalsWrap(HelpTestCase):
3514 """Test usage messages where the prog is long and the positionals wrap"""
3515
3516 parser_signature = Sig(prog='P' * 60, add_help=False)
3517 argument_signatures = [
3518 Sig('a' * 25),
3519 Sig('b' * 25),
3520 Sig('c' * 25),
3521 ]
3522 argument_group_signatures = []
3523 usage = '''\
3524 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3525 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3526 ccccccccccccccccccccccccc
3527 '''
3528 help = usage + '''\
3529
3530 positional arguments:
3531 aaaaaaaaaaaaaaaaaaaaaaaaa
3532 bbbbbbbbbbbbbbbbbbbbbbbbb
3533 ccccccccccccccccccccccccc
3534 '''
3535 version = ''
3536
3537
3538class TestHelpUsageOptionalsWrap(HelpTestCase):
3539 """Test usage messages where the optionals wrap"""
3540
3541 parser_signature = Sig(prog='PROG')
3542 argument_signatures = [
3543 Sig('-w', metavar='W' * 25),
3544 Sig('-x', metavar='X' * 25),
3545 Sig('-y', metavar='Y' * 25),
3546 Sig('-z', metavar='Z' * 25),
3547 Sig('a'),
3548 Sig('b'),
3549 Sig('c'),
3550 ]
3551 argument_group_signatures = []
3552 usage = '''\
3553 usage: PROG [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3554[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3555 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] \
3556[-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3557 a b c
3558 '''
3559 help = usage + '''\
3560
3561 positional arguments:
3562 a
3563 b
3564 c
3565
3566 optional arguments:
3567 -h, --help show this help message and exit
3568 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3569 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3570 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3571 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3572 '''
3573 version = ''
3574
3575
3576class TestHelpUsagePositionalsWrap(HelpTestCase):
3577 """Test usage messages where the positionals wrap"""
3578
3579 parser_signature = Sig(prog='PROG')
3580 argument_signatures = [
3581 Sig('-x'),
3582 Sig('-y'),
3583 Sig('-z'),
3584 Sig('a' * 25),
3585 Sig('b' * 25),
3586 Sig('c' * 25),
3587 ]
3588 argument_group_signatures = []
3589 usage = '''\
3590 usage: PROG [-h] [-x X] [-y Y] [-z Z]
3591 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3592 ccccccccccccccccccccccccc
3593 '''
3594 help = usage + '''\
3595
3596 positional arguments:
3597 aaaaaaaaaaaaaaaaaaaaaaaaa
3598 bbbbbbbbbbbbbbbbbbbbbbbbb
3599 ccccccccccccccccccccccccc
3600
3601 optional arguments:
3602 -h, --help show this help message and exit
3603 -x X
3604 -y Y
3605 -z Z
3606 '''
3607 version = ''
3608
3609
3610class TestHelpUsageOptionalsPositionalsWrap(HelpTestCase):
3611 """Test usage messages where the optionals and positionals wrap"""
3612
3613 parser_signature = Sig(prog='PROG')
3614 argument_signatures = [
3615 Sig('-x', metavar='X' * 25),
3616 Sig('-y', metavar='Y' * 25),
3617 Sig('-z', metavar='Z' * 25),
3618 Sig('a' * 25),
3619 Sig('b' * 25),
3620 Sig('c' * 25),
3621 ]
3622 argument_group_signatures = []
3623 usage = '''\
3624 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3625[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3626 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3627 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3628 ccccccccccccccccccccccccc
3629 '''
3630 help = usage + '''\
3631
3632 positional arguments:
3633 aaaaaaaaaaaaaaaaaaaaaaaaa
3634 bbbbbbbbbbbbbbbbbbbbbbbbb
3635 ccccccccccccccccccccccccc
3636
3637 optional arguments:
3638 -h, --help show this help message and exit
3639 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3640 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3641 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3642 '''
3643 version = ''
3644
3645
3646class TestHelpUsageOptionalsOnlyWrap(HelpTestCase):
3647 """Test usage messages where there are only optionals and they wrap"""
3648
3649 parser_signature = Sig(prog='PROG')
3650 argument_signatures = [
3651 Sig('-x', metavar='X' * 25),
3652 Sig('-y', metavar='Y' * 25),
3653 Sig('-z', metavar='Z' * 25),
3654 ]
3655 argument_group_signatures = []
3656 usage = '''\
3657 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3658[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3659 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3660 '''
3661 help = usage + '''\
3662
3663 optional arguments:
3664 -h, --help show this help message and exit
3665 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3666 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3667 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3668 '''
3669 version = ''
3670
3671
3672class TestHelpUsagePositionalsOnlyWrap(HelpTestCase):
3673 """Test usage messages where there are only positionals and they wrap"""
3674
3675 parser_signature = Sig(prog='PROG', add_help=False)
3676 argument_signatures = [
3677 Sig('a' * 25),
3678 Sig('b' * 25),
3679 Sig('c' * 25),
3680 ]
3681 argument_group_signatures = []
3682 usage = '''\
3683 usage: PROG aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3684 ccccccccccccccccccccccccc
3685 '''
3686 help = usage + '''\
3687
3688 positional arguments:
3689 aaaaaaaaaaaaaaaaaaaaaaaaa
3690 bbbbbbbbbbbbbbbbbbbbbbbbb
3691 ccccccccccccccccccccccccc
3692 '''
3693 version = ''
3694
3695
3696class TestHelpVariableExpansion(HelpTestCase):
3697 """Test that variables are expanded properly in help messages"""
3698
3699 parser_signature = Sig(prog='PROG')
3700 argument_signatures = [
3701 Sig('-x', type=int,
3702 help='x %(prog)s %(default)s %(type)s %%'),
3703 Sig('-y', action='store_const', default=42, const='XXX',
3704 help='y %(prog)s %(default)s %(const)s'),
3705 Sig('--foo', choices='abc',
3706 help='foo %(prog)s %(default)s %(choices)s'),
3707 Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
3708 help='bar %(prog)s %(default)s %(dest)s'),
3709 Sig('spam', help='spam %(prog)s %(default)s'),
3710 Sig('badger', default=0.5, help='badger %(prog)s %(default)s'),
3711 ]
3712 argument_group_signatures = [
3713 (Sig('group'), [
3714 Sig('-a', help='a %(prog)s %(default)s'),
3715 Sig('-b', default=-1, help='b %(prog)s %(default)s'),
3716 ])
3717 ]
3718 usage = ('''\
3719 usage: PROG [-h] [-x X] [-y] [--foo {a,b,c}] [--bar BBB] [-a A] [-b B]
3720 spam badger
3721 ''')
3722 help = usage + '''\
3723
3724 positional arguments:
3725 spam spam PROG None
3726 badger badger PROG 0.5
3727
3728 optional arguments:
3729 -h, --help show this help message and exit
3730 -x X x PROG None int %
3731 -y y PROG 42 XXX
3732 --foo {a,b,c} foo PROG None a, b, c
3733 --bar BBB bar PROG baz bar
3734
3735 group:
3736 -a A a PROG None
3737 -b B b PROG -1
3738 '''
3739 version = ''
3740
3741
3742class TestHelpVariableExpansionUsageSupplied(HelpTestCase):
3743 """Test that variables are expanded properly when usage= is present"""
3744
3745 parser_signature = Sig(prog='PROG', usage='%(prog)s FOO')
3746 argument_signatures = []
3747 argument_group_signatures = []
3748 usage = ('''\
3749 usage: PROG FOO
3750 ''')
3751 help = usage + '''\
3752
3753 optional arguments:
3754 -h, --help show this help message and exit
3755 '''
3756 version = ''
3757
3758
3759class TestHelpVariableExpansionNoArguments(HelpTestCase):
3760 """Test that variables are expanded properly with no arguments"""
3761
3762 parser_signature = Sig(prog='PROG', add_help=False)
3763 argument_signatures = []
3764 argument_group_signatures = []
3765 usage = ('''\
3766 usage: PROG
3767 ''')
3768 help = usage
3769 version = ''
3770
3771
3772class TestHelpSuppressUsage(HelpTestCase):
3773 """Test that items can be suppressed in usage messages"""
3774
3775 parser_signature = Sig(prog='PROG', usage=argparse.SUPPRESS)
3776 argument_signatures = [
3777 Sig('--foo', help='foo help'),
3778 Sig('spam', help='spam help'),
3779 ]
3780 argument_group_signatures = []
3781 help = '''\
3782 positional arguments:
3783 spam spam help
3784
3785 optional arguments:
3786 -h, --help show this help message and exit
3787 --foo FOO foo help
3788 '''
3789 usage = ''
3790 version = ''
3791
3792
3793class TestHelpSuppressOptional(HelpTestCase):
3794 """Test that optional arguments can be suppressed in help messages"""
3795
3796 parser_signature = Sig(prog='PROG', add_help=False)
3797 argument_signatures = [
3798 Sig('--foo', help=argparse.SUPPRESS),
3799 Sig('spam', help='spam help'),
3800 ]
3801 argument_group_signatures = []
3802 usage = '''\
3803 usage: PROG spam
3804 '''
3805 help = usage + '''\
3806
3807 positional arguments:
3808 spam spam help
3809 '''
3810 version = ''
3811
3812
3813class TestHelpSuppressOptionalGroup(HelpTestCase):
3814 """Test that optional groups can be suppressed in help messages"""
3815
3816 parser_signature = Sig(prog='PROG')
3817 argument_signatures = [
3818 Sig('--foo', help='foo help'),
3819 Sig('spam', help='spam help'),
3820 ]
3821 argument_group_signatures = [
3822 (Sig('group'), [Sig('--bar', help=argparse.SUPPRESS)]),
3823 ]
3824 usage = '''\
3825 usage: PROG [-h] [--foo FOO] spam
3826 '''
3827 help = usage + '''\
3828
3829 positional arguments:
3830 spam spam help
3831
3832 optional arguments:
3833 -h, --help show this help message and exit
3834 --foo FOO foo help
3835 '''
3836 version = ''
3837
3838
3839class TestHelpSuppressPositional(HelpTestCase):
3840 """Test that positional arguments can be suppressed in help messages"""
3841
3842 parser_signature = Sig(prog='PROG')
3843 argument_signatures = [
3844 Sig('--foo', help='foo help'),
3845 Sig('spam', help=argparse.SUPPRESS),
3846 ]
3847 argument_group_signatures = []
3848 usage = '''\
3849 usage: PROG [-h] [--foo FOO]
3850 '''
3851 help = usage + '''\
3852
3853 optional arguments:
3854 -h, --help show this help message and exit
3855 --foo FOO foo help
3856 '''
3857 version = ''
3858
3859
3860class TestHelpRequiredOptional(HelpTestCase):
3861 """Test that required options don't look optional"""
3862
3863 parser_signature = Sig(prog='PROG')
3864 argument_signatures = [
3865 Sig('--foo', required=True, help='foo help'),
3866 ]
3867 argument_group_signatures = []
3868 usage = '''\
3869 usage: PROG [-h] --foo FOO
3870 '''
3871 help = usage + '''\
3872
3873 optional arguments:
3874 -h, --help show this help message and exit
3875 --foo FOO foo help
3876 '''
3877 version = ''
3878
3879
3880class TestHelpAlternatePrefixChars(HelpTestCase):
3881 """Test that options display with different prefix characters"""
3882
3883 parser_signature = Sig(prog='PROG', prefix_chars='^;', add_help=False)
3884 argument_signatures = [
3885 Sig('^^foo', action='store_true', help='foo help'),
3886 Sig(';b', ';;bar', help='bar help'),
3887 ]
3888 argument_group_signatures = []
3889 usage = '''\
3890 usage: PROG [^^foo] [;b BAR]
3891 '''
3892 help = usage + '''\
3893
3894 optional arguments:
3895 ^^foo foo help
3896 ;b BAR, ;;bar BAR bar help
3897 '''
3898 version = ''
3899
3900
3901class TestHelpNoHelpOptional(HelpTestCase):
3902 """Test that the --help argument can be suppressed help messages"""
3903
3904 parser_signature = Sig(prog='PROG', add_help=False)
3905 argument_signatures = [
3906 Sig('--foo', help='foo help'),
3907 Sig('spam', help='spam help'),
3908 ]
3909 argument_group_signatures = []
3910 usage = '''\
3911 usage: PROG [--foo FOO] spam
3912 '''
3913 help = usage + '''\
3914
3915 positional arguments:
3916 spam spam help
3917
3918 optional arguments:
3919 --foo FOO foo help
3920 '''
3921 version = ''
3922
3923
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003924class TestHelpNone(HelpTestCase):
3925 """Test that no errors occur if no help is specified"""
3926
3927 parser_signature = Sig(prog='PROG')
3928 argument_signatures = [
3929 Sig('--foo'),
3930 Sig('spam'),
3931 ]
3932 argument_group_signatures = []
3933 usage = '''\
3934 usage: PROG [-h] [--foo FOO] spam
3935 '''
3936 help = usage + '''\
3937
3938 positional arguments:
3939 spam
3940
3941 optional arguments:
3942 -h, --help show this help message and exit
3943 --foo FOO
3944 '''
3945 version = ''
3946
3947
3948class TestHelpTupleMetavar(HelpTestCase):
3949 """Test specifying metavar as a tuple"""
3950
3951 parser_signature = Sig(prog='PROG')
3952 argument_signatures = [
3953 Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
3954 Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
3955 Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
3956 Sig('-z', help='z', nargs='?', metavar=('Z1', )),
3957 ]
3958 argument_group_signatures = []
3959 usage = '''\
3960 usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
3961[-z [Z1]]
3962 '''
3963 help = usage + '''\
3964
3965 optional arguments:
3966 -h, --help show this help message and exit
3967 -w W1 [W2 ...] w
3968 -x [X1 [X2 ...]] x
3969 -y Y1 Y2 Y3 y
3970 -z [Z1] z
3971 '''
3972 version = ''
3973
3974
3975class TestHelpRawText(HelpTestCase):
3976 """Test the RawTextHelpFormatter"""
3977
3978 parser_signature = Sig(
3979 prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
3980 description='Keep the formatting\n'
3981 ' exactly as it is written\n'
3982 '\n'
3983 'here\n')
3984
3985 argument_signatures = [
3986 Sig('--foo', help=' foo help should also\n'
3987 'appear as given here'),
3988 Sig('spam', help='spam help'),
3989 ]
3990 argument_group_signatures = [
3991 (Sig('title', description=' This text\n'
3992 ' should be indented\n'
3993 ' exactly like it is here\n'),
3994 [Sig('--bar', help='bar help')]),
3995 ]
3996 usage = '''\
3997 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3998 '''
3999 help = usage + '''\
4000
4001 Keep the formatting
4002 exactly as it is written
4003
4004 here
4005
4006 positional arguments:
4007 spam spam help
4008
4009 optional arguments:
4010 -h, --help show this help message and exit
4011 --foo FOO foo help should also
4012 appear as given here
4013
4014 title:
4015 This text
4016 should be indented
4017 exactly like it is here
4018
4019 --bar BAR bar help
4020 '''
4021 version = ''
4022
4023
4024class TestHelpRawDescription(HelpTestCase):
4025 """Test the RawTextHelpFormatter"""
4026
4027 parser_signature = Sig(
4028 prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
4029 description='Keep the formatting\n'
4030 ' exactly as it is written\n'
4031 '\n'
4032 'here\n')
4033
4034 argument_signatures = [
4035 Sig('--foo', help=' foo help should not\n'
4036 ' retain this odd formatting'),
4037 Sig('spam', help='spam help'),
4038 ]
4039 argument_group_signatures = [
4040 (Sig('title', description=' This text\n'
4041 ' should be indented\n'
4042 ' exactly like it is here\n'),
4043 [Sig('--bar', help='bar help')]),
4044 ]
4045 usage = '''\
4046 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
4047 '''
4048 help = usage + '''\
4049
4050 Keep the formatting
4051 exactly as it is written
4052
4053 here
4054
4055 positional arguments:
4056 spam spam help
4057
4058 optional arguments:
4059 -h, --help show this help message and exit
4060 --foo FOO foo help should not retain this odd formatting
4061
4062 title:
4063 This text
4064 should be indented
4065 exactly like it is here
4066
4067 --bar BAR bar help
4068 '''
4069 version = ''
4070
4071
4072class TestHelpArgumentDefaults(HelpTestCase):
4073 """Test the ArgumentDefaultsHelpFormatter"""
4074
4075 parser_signature = Sig(
4076 prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
4077 description='description')
4078
4079 argument_signatures = [
4080 Sig('--foo', help='foo help - oh and by the way, %(default)s'),
4081 Sig('--bar', action='store_true', help='bar help'),
4082 Sig('spam', help='spam help'),
4083 Sig('badger', nargs='?', default='wooden', help='badger help'),
4084 ]
4085 argument_group_signatures = [
4086 (Sig('title', description='description'),
4087 [Sig('--baz', type=int, default=42, help='baz help')]),
4088 ]
4089 usage = '''\
4090 usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
4091 '''
4092 help = usage + '''\
4093
4094 description
4095
4096 positional arguments:
4097 spam spam help
4098 badger badger help (default: wooden)
4099
4100 optional arguments:
4101 -h, --help show this help message and exit
4102 --foo FOO foo help - oh and by the way, None
4103 --bar bar help (default: False)
4104
4105 title:
4106 description
4107
4108 --baz BAZ baz help (default: 42)
4109 '''
4110 version = ''
4111
Steven Bethard50fe5932010-05-24 03:47:38 +00004112class TestHelpVersionAction(HelpTestCase):
4113 """Test the default help for the version action"""
4114
4115 parser_signature = Sig(prog='PROG', description='description')
4116 argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
4117 argument_group_signatures = []
4118 usage = '''\
4119 usage: PROG [-h] [-V]
4120 '''
4121 help = usage + '''\
4122
4123 description
4124
4125 optional arguments:
4126 -h, --help show this help message and exit
4127 -V, --version show program's version number and exit
4128 '''
4129 version = ''
4130
Berker Peksagecb75e22015-04-10 16:11:12 +03004131
4132class TestHelpVersionActionSuppress(HelpTestCase):
4133 """Test that the --version argument can be suppressed in help messages"""
4134
4135 parser_signature = Sig(prog='PROG')
4136 argument_signatures = [
4137 Sig('-v', '--version', action='version', version='1.0',
4138 help=argparse.SUPPRESS),
4139 Sig('--foo', help='foo help'),
4140 Sig('spam', help='spam help'),
4141 ]
4142 argument_group_signatures = []
4143 usage = '''\
4144 usage: PROG [-h] [--foo FOO] spam
4145 '''
4146 help = usage + '''\
4147
4148 positional arguments:
4149 spam spam help
4150
4151 optional arguments:
4152 -h, --help show this help message and exit
4153 --foo FOO foo help
4154 '''
4155
4156
Steven Bethard8a6a1982011-03-27 13:53:53 +02004157class TestHelpSubparsersOrdering(HelpTestCase):
4158 """Test ordering of subcommands in help matches the code"""
4159 parser_signature = Sig(prog='PROG',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004160 description='display some subcommands')
4161 argument_signatures = [Sig('-v', '--version', action='version', version='0.1')]
Steven Bethard8a6a1982011-03-27 13:53:53 +02004162
4163 subparsers_signatures = [Sig(name=name)
4164 for name in ('a', 'b', 'c', 'd', 'e')]
4165
4166 usage = '''\
4167 usage: PROG [-h] [-v] {a,b,c,d,e} ...
4168 '''
4169
4170 help = usage + '''\
4171
4172 display some subcommands
4173
4174 positional arguments:
4175 {a,b,c,d,e}
4176
4177 optional arguments:
4178 -h, --help show this help message and exit
4179 -v, --version show program's version number and exit
4180 '''
4181
4182 version = '''\
4183 0.1
4184 '''
4185
4186class TestHelpSubparsersWithHelpOrdering(HelpTestCase):
4187 """Test ordering of subcommands in help matches the code"""
4188 parser_signature = Sig(prog='PROG',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004189 description='display some subcommands')
4190 argument_signatures = [Sig('-v', '--version', action='version', version='0.1')]
Steven Bethard8a6a1982011-03-27 13:53:53 +02004191
4192 subcommand_data = (('a', 'a subcommand help'),
4193 ('b', 'b subcommand help'),
4194 ('c', 'c subcommand help'),
4195 ('d', 'd subcommand help'),
4196 ('e', 'e subcommand help'),
4197 )
4198
4199 subparsers_signatures = [Sig(name=name, help=help)
4200 for name, help in subcommand_data]
4201
4202 usage = '''\
4203 usage: PROG [-h] [-v] {a,b,c,d,e} ...
4204 '''
4205
4206 help = usage + '''\
4207
4208 display some subcommands
4209
4210 positional arguments:
4211 {a,b,c,d,e}
4212 a a subcommand help
4213 b b subcommand help
4214 c c subcommand help
4215 d d subcommand help
4216 e e subcommand help
4217
4218 optional arguments:
4219 -h, --help show this help message and exit
4220 -v, --version show program's version number and exit
4221 '''
4222
4223 version = '''\
4224 0.1
4225 '''
4226
4227
Steven Bethard0331e902011-03-26 14:48:04 +01004228
4229class TestHelpMetavarTypeFormatter(HelpTestCase):
4230 """"""
4231
4232 def custom_type(string):
4233 return string
4234
4235 parser_signature = Sig(prog='PROG', description='description',
4236 formatter_class=argparse.MetavarTypeHelpFormatter)
4237 argument_signatures = [Sig('a', type=int),
4238 Sig('-b', type=custom_type),
4239 Sig('-c', type=float, metavar='SOME FLOAT')]
4240 argument_group_signatures = []
4241 usage = '''\
4242 usage: PROG [-h] [-b custom_type] [-c SOME FLOAT] int
4243 '''
4244 help = usage + '''\
4245
4246 description
4247
4248 positional arguments:
4249 int
4250
4251 optional arguments:
4252 -h, --help show this help message and exit
4253 -b custom_type
4254 -c SOME FLOAT
4255 '''
4256 version = ''
4257
4258
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004259# =====================================
4260# Optional/Positional constructor tests
4261# =====================================
4262
4263class TestInvalidArgumentConstructors(TestCase):
4264 """Test a bunch of invalid Argument constructors"""
4265
4266 def assertTypeError(self, *args, **kwargs):
4267 parser = argparse.ArgumentParser()
4268 self.assertRaises(TypeError, parser.add_argument,
4269 *args, **kwargs)
4270
4271 def assertValueError(self, *args, **kwargs):
4272 parser = argparse.ArgumentParser()
4273 self.assertRaises(ValueError, parser.add_argument,
4274 *args, **kwargs)
4275
4276 def test_invalid_keyword_arguments(self):
4277 self.assertTypeError('-x', bar=None)
4278 self.assertTypeError('-y', callback='foo')
4279 self.assertTypeError('-y', callback_args=())
4280 self.assertTypeError('-y', callback_kwargs={})
4281
4282 def test_missing_destination(self):
4283 self.assertTypeError()
4284 for action in ['append', 'store']:
4285 self.assertTypeError(action=action)
4286
4287 def test_invalid_option_strings(self):
4288 self.assertValueError('--')
4289 self.assertValueError('---')
4290
4291 def test_invalid_type(self):
4292 self.assertValueError('--foo', type='int')
Steven Bethard7cb20a82011-04-04 01:53:02 +02004293 self.assertValueError('--foo', type=(int, float))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004294
4295 def test_invalid_action(self):
4296 self.assertValueError('-x', action='foo')
4297 self.assertValueError('foo', action='baz')
Steven Bethard7cb20a82011-04-04 01:53:02 +02004298 self.assertValueError('--foo', action=('store', 'append'))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004299 parser = argparse.ArgumentParser()
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004300 with self.assertRaises(ValueError) as cm:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004301 parser.add_argument("--foo", action="store-true")
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004302 self.assertIn('unknown action', str(cm.exception))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004303
4304 def test_multiple_dest(self):
4305 parser = argparse.ArgumentParser()
4306 parser.add_argument(dest='foo')
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004307 with self.assertRaises(ValueError) as cm:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004308 parser.add_argument('bar', dest='baz')
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004309 self.assertIn('dest supplied twice for positional argument',
4310 str(cm.exception))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004311
4312 def test_no_argument_actions(self):
4313 for action in ['store_const', 'store_true', 'store_false',
4314 'append_const', 'count']:
4315 for attrs in [dict(type=int), dict(nargs='+'),
4316 dict(choices='ab')]:
4317 self.assertTypeError('-x', action=action, **attrs)
4318
4319 def test_no_argument_no_const_actions(self):
4320 # options with zero arguments
4321 for action in ['store_true', 'store_false', 'count']:
4322
4323 # const is always disallowed
4324 self.assertTypeError('-x', const='foo', action=action)
4325
4326 # nargs is always disallowed
4327 self.assertTypeError('-x', nargs='*', action=action)
4328
4329 def test_more_than_one_argument_actions(self):
4330 for action in ['store', 'append']:
4331
4332 # nargs=0 is disallowed
4333 self.assertValueError('-x', nargs=0, action=action)
4334 self.assertValueError('spam', nargs=0, action=action)
4335
4336 # const is disallowed with non-optional arguments
4337 for nargs in [1, '*', '+']:
4338 self.assertValueError('-x', const='foo',
4339 nargs=nargs, action=action)
4340 self.assertValueError('spam', const='foo',
4341 nargs=nargs, action=action)
4342
4343 def test_required_const_actions(self):
4344 for action in ['store_const', 'append_const']:
4345
4346 # nargs is always disallowed
4347 self.assertTypeError('-x', nargs='+', action=action)
4348
4349 def test_parsers_action_missing_params(self):
4350 self.assertTypeError('command', action='parsers')
4351 self.assertTypeError('command', action='parsers', prog='PROG')
4352 self.assertTypeError('command', action='parsers',
4353 parser_class=argparse.ArgumentParser)
4354
4355 def test_required_positional(self):
4356 self.assertTypeError('foo', required=True)
4357
4358 def test_user_defined_action(self):
4359
4360 class Success(Exception):
4361 pass
4362
4363 class Action(object):
4364
4365 def __init__(self,
4366 option_strings,
4367 dest,
4368 const,
4369 default,
4370 required=False):
4371 if dest == 'spam':
4372 if const is Success:
4373 if default is Success:
4374 raise Success()
4375
4376 def __call__(self, *args, **kwargs):
4377 pass
4378
4379 parser = argparse.ArgumentParser()
4380 self.assertRaises(Success, parser.add_argument, '--spam',
4381 action=Action, default=Success, const=Success)
4382 self.assertRaises(Success, parser.add_argument, 'spam',
4383 action=Action, default=Success, const=Success)
4384
4385# ================================
4386# Actions returned by add_argument
4387# ================================
4388
4389class TestActionsReturned(TestCase):
4390
4391 def test_dest(self):
4392 parser = argparse.ArgumentParser()
4393 action = parser.add_argument('--foo')
4394 self.assertEqual(action.dest, 'foo')
4395 action = parser.add_argument('-b', '--bar')
4396 self.assertEqual(action.dest, 'bar')
4397 action = parser.add_argument('-x', '-y')
4398 self.assertEqual(action.dest, 'x')
4399
4400 def test_misc(self):
4401 parser = argparse.ArgumentParser()
4402 action = parser.add_argument('--foo', nargs='?', const=42,
4403 default=84, type=int, choices=[1, 2],
4404 help='FOO', metavar='BAR', dest='baz')
4405 self.assertEqual(action.nargs, '?')
4406 self.assertEqual(action.const, 42)
4407 self.assertEqual(action.default, 84)
4408 self.assertEqual(action.type, int)
4409 self.assertEqual(action.choices, [1, 2])
4410 self.assertEqual(action.help, 'FOO')
4411 self.assertEqual(action.metavar, 'BAR')
4412 self.assertEqual(action.dest, 'baz')
4413
4414
4415# ================================
4416# Argument conflict handling tests
4417# ================================
4418
4419class TestConflictHandling(TestCase):
4420
4421 def test_bad_type(self):
4422 self.assertRaises(ValueError, argparse.ArgumentParser,
4423 conflict_handler='foo')
4424
4425 def test_conflict_error(self):
4426 parser = argparse.ArgumentParser()
4427 parser.add_argument('-x')
4428 self.assertRaises(argparse.ArgumentError,
4429 parser.add_argument, '-x')
4430 parser.add_argument('--spam')
4431 self.assertRaises(argparse.ArgumentError,
4432 parser.add_argument, '--spam')
4433
4434 def test_resolve_error(self):
4435 get_parser = argparse.ArgumentParser
4436 parser = get_parser(prog='PROG', conflict_handler='resolve')
4437
4438 parser.add_argument('-x', help='OLD X')
4439 parser.add_argument('-x', help='NEW X')
4440 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4441 usage: PROG [-h] [-x X]
4442
4443 optional arguments:
4444 -h, --help show this help message and exit
4445 -x X NEW X
4446 '''))
4447
4448 parser.add_argument('--spam', metavar='OLD_SPAM')
4449 parser.add_argument('--spam', metavar='NEW_SPAM')
4450 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4451 usage: PROG [-h] [-x X] [--spam NEW_SPAM]
4452
4453 optional arguments:
4454 -h, --help show this help message and exit
4455 -x X NEW X
4456 --spam NEW_SPAM
4457 '''))
4458
4459
4460# =============================
4461# Help and Version option tests
4462# =============================
4463
4464class TestOptionalsHelpVersionActions(TestCase):
4465 """Test the help and version actions"""
4466
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004467 def assertPrintHelpExit(self, parser, args_str):
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004468 with self.assertRaises(ArgumentParserError) as cm:
4469 parser.parse_args(args_str.split())
4470 self.assertEqual(parser.format_help(), cm.exception.stdout)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004471
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004472 def assertArgumentParserError(self, parser, *args):
4473 self.assertRaises(ArgumentParserError, parser.parse_args, args)
4474
4475 def test_version(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004476 parser = ErrorRaisingArgumentParser()
4477 parser.add_argument('-v', '--version', action='version', version='1.0')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004478 self.assertPrintHelpExit(parser, '-h')
4479 self.assertPrintHelpExit(parser, '--help')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004480 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004481
4482 def test_version_format(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004483 parser = ErrorRaisingArgumentParser(prog='PPP')
4484 parser.add_argument('-v', '--version', action='version', version='%(prog)s 3.5')
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004485 with self.assertRaises(ArgumentParserError) as cm:
4486 parser.parse_args(['-v'])
4487 self.assertEqual('PPP 3.5\n', cm.exception.stdout)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004488
4489 def test_version_no_help(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004490 parser = ErrorRaisingArgumentParser(add_help=False)
4491 parser.add_argument('-v', '--version', action='version', version='1.0')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004492 self.assertArgumentParserError(parser, '-h')
4493 self.assertArgumentParserError(parser, '--help')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004494 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004495
4496 def test_version_action(self):
4497 parser = ErrorRaisingArgumentParser(prog='XXX')
4498 parser.add_argument('-V', action='version', version='%(prog)s 3.7')
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004499 with self.assertRaises(ArgumentParserError) as cm:
4500 parser.parse_args(['-V'])
4501 self.assertEqual('XXX 3.7\n', cm.exception.stdout)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004502
4503 def test_no_help(self):
4504 parser = ErrorRaisingArgumentParser(add_help=False)
4505 self.assertArgumentParserError(parser, '-h')
4506 self.assertArgumentParserError(parser, '--help')
4507 self.assertArgumentParserError(parser, '-v')
4508 self.assertArgumentParserError(parser, '--version')
4509
4510 def test_alternate_help_version(self):
4511 parser = ErrorRaisingArgumentParser()
4512 parser.add_argument('-x', action='help')
4513 parser.add_argument('-y', action='version')
4514 self.assertPrintHelpExit(parser, '-x')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004515 self.assertArgumentParserError(parser, '-v')
4516 self.assertArgumentParserError(parser, '--version')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004517 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004518
4519 def test_help_version_extra_arguments(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004520 parser = ErrorRaisingArgumentParser()
4521 parser.add_argument('--version', action='version', version='1.0')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004522 parser.add_argument('-x', action='store_true')
4523 parser.add_argument('y')
4524
4525 # try all combinations of valid prefixes and suffixes
4526 valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
4527 valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
4528 for prefix in valid_prefixes:
4529 for suffix in valid_suffixes:
4530 format = '%s %%s %s' % (prefix, suffix)
4531 self.assertPrintHelpExit(parser, format % '-h')
4532 self.assertPrintHelpExit(parser, format % '--help')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004533 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004534
4535
4536# ======================
4537# str() and repr() tests
4538# ======================
4539
4540class TestStrings(TestCase):
4541 """Test str() and repr() on Optionals and Positionals"""
4542
4543 def assertStringEqual(self, obj, result_string):
4544 for func in [str, repr]:
4545 self.assertEqual(func(obj), result_string)
4546
4547 def test_optional(self):
4548 option = argparse.Action(
4549 option_strings=['--foo', '-a', '-b'],
4550 dest='b',
4551 type='int',
4552 nargs='+',
4553 default=42,
4554 choices=[1, 2, 3],
4555 help='HELP',
4556 metavar='METAVAR')
4557 string = (
4558 "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
4559 "nargs='+', const=None, default=42, type='int', "
4560 "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
4561 self.assertStringEqual(option, string)
4562
4563 def test_argument(self):
4564 argument = argparse.Action(
4565 option_strings=[],
4566 dest='x',
4567 type=float,
4568 nargs='?',
4569 default=2.5,
4570 choices=[0.5, 1.5, 2.5],
4571 help='H HH H',
4572 metavar='MV MV MV')
4573 string = (
4574 "Action(option_strings=[], dest='x', nargs='?', "
4575 "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
4576 "help='H HH H', metavar='MV MV MV')" % float)
4577 self.assertStringEqual(argument, string)
4578
4579 def test_namespace(self):
4580 ns = argparse.Namespace(foo=42, bar='spam')
4581 string = "Namespace(bar='spam', foo=42)"
4582 self.assertStringEqual(ns, string)
4583
Berker Peksag76b17142015-07-29 23:51:47 +03004584 def test_namespace_starkwargs_notidentifier(self):
4585 ns = argparse.Namespace(**{'"': 'quote'})
4586 string = """Namespace(**{'"': 'quote'})"""
4587 self.assertStringEqual(ns, string)
4588
4589 def test_namespace_kwargs_and_starkwargs_notidentifier(self):
4590 ns = argparse.Namespace(a=1, **{'"': 'quote'})
4591 string = """Namespace(a=1, **{'"': 'quote'})"""
4592 self.assertStringEqual(ns, string)
4593
4594 def test_namespace_starkwargs_identifier(self):
4595 ns = argparse.Namespace(**{'valid': True})
4596 string = "Namespace(valid=True)"
4597 self.assertStringEqual(ns, string)
4598
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004599 def test_parser(self):
4600 parser = argparse.ArgumentParser(prog='PROG')
4601 string = (
4602 "ArgumentParser(prog='PROG', usage=None, description=None, "
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004603 "formatter_class=%r, conflict_handler='error', "
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004604 "add_help=True)" % argparse.HelpFormatter)
4605 self.assertStringEqual(parser, string)
4606
4607# ===============
4608# Namespace tests
4609# ===============
4610
4611class TestNamespace(TestCase):
4612
4613 def test_constructor(self):
4614 ns = argparse.Namespace()
4615 self.assertRaises(AttributeError, getattr, ns, 'x')
4616
4617 ns = argparse.Namespace(a=42, b='spam')
4618 self.assertEqual(ns.a, 42)
4619 self.assertEqual(ns.b, 'spam')
4620
4621 def test_equality(self):
4622 ns1 = argparse.Namespace(a=1, b=2)
4623 ns2 = argparse.Namespace(b=2, a=1)
4624 ns3 = argparse.Namespace(a=1)
4625 ns4 = argparse.Namespace(b=2)
4626
4627 self.assertEqual(ns1, ns2)
4628 self.assertNotEqual(ns1, ns3)
4629 self.assertNotEqual(ns1, ns4)
4630 self.assertNotEqual(ns2, ns3)
4631 self.assertNotEqual(ns2, ns4)
4632 self.assertTrue(ns1 != ns3)
4633 self.assertTrue(ns1 != ns4)
4634 self.assertTrue(ns2 != ns3)
4635 self.assertTrue(ns2 != ns4)
4636
Berker Peksagc16387b2016-09-28 17:21:52 +03004637 def test_equality_returns_notimplemented(self):
Raymond Hettingerdea46ec2014-05-26 00:43:27 -07004638 # See issue 21481
4639 ns = argparse.Namespace(a=1, b=2)
4640 self.assertIs(ns.__eq__(None), NotImplemented)
4641 self.assertIs(ns.__ne__(None), NotImplemented)
4642
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004643
4644# ===================
4645# File encoding tests
4646# ===================
4647
4648class TestEncoding(TestCase):
4649
4650 def _test_module_encoding(self, path):
4651 path, _ = os.path.splitext(path)
4652 path += ".py"
Victor Stinner272d8882017-06-16 08:59:01 +02004653 with open(path, 'r', encoding='utf-8') as f:
Antoine Pitroub86680e2010-10-14 21:15:17 +00004654 f.read()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004655
4656 def test_argparse_module_encoding(self):
4657 self._test_module_encoding(argparse.__file__)
4658
4659 def test_test_argparse_module_encoding(self):
4660 self._test_module_encoding(__file__)
4661
4662# ===================
4663# ArgumentError tests
4664# ===================
4665
4666class TestArgumentError(TestCase):
4667
4668 def test_argument_error(self):
4669 msg = "my error here"
4670 error = argparse.ArgumentError(None, msg)
4671 self.assertEqual(str(error), msg)
4672
4673# =======================
4674# ArgumentTypeError tests
4675# =======================
4676
R. David Murray722b5fd2010-11-20 03:48:58 +00004677class TestArgumentTypeError(TestCase):
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004678
4679 def test_argument_type_error(self):
4680
4681 def spam(string):
4682 raise argparse.ArgumentTypeError('spam!')
4683
4684 parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
4685 parser.add_argument('x', type=spam)
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004686 with self.assertRaises(ArgumentParserError) as cm:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004687 parser.parse_args(['XXX'])
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004688 self.assertEqual('usage: PROG x\nPROG: error: argument x: spam!\n',
4689 cm.exception.stderr)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004690
R David Murrayf97c59a2011-06-09 12:34:07 -04004691# =========================
4692# MessageContentError tests
4693# =========================
4694
4695class TestMessageContentError(TestCase):
4696
4697 def test_missing_argument_name_in_message(self):
4698 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4699 parser.add_argument('req_pos', type=str)
4700 parser.add_argument('-req_opt', type=int, required=True)
4701 parser.add_argument('need_one', type=str, nargs='+')
4702
4703 with self.assertRaises(ArgumentParserError) as cm:
4704 parser.parse_args([])
4705 msg = str(cm.exception)
4706 self.assertRegex(msg, 'req_pos')
4707 self.assertRegex(msg, 'req_opt')
4708 self.assertRegex(msg, 'need_one')
4709 with self.assertRaises(ArgumentParserError) as cm:
4710 parser.parse_args(['myXargument'])
4711 msg = str(cm.exception)
4712 self.assertNotIn(msg, 'req_pos')
4713 self.assertRegex(msg, 'req_opt')
4714 self.assertRegex(msg, 'need_one')
4715 with self.assertRaises(ArgumentParserError) as cm:
4716 parser.parse_args(['myXargument', '-req_opt=1'])
4717 msg = str(cm.exception)
4718 self.assertNotIn(msg, 'req_pos')
4719 self.assertNotIn(msg, 'req_opt')
4720 self.assertRegex(msg, 'need_one')
4721
4722 def test_optional_optional_not_in_message(self):
4723 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4724 parser.add_argument('req_pos', type=str)
4725 parser.add_argument('--req_opt', type=int, required=True)
4726 parser.add_argument('--opt_opt', type=bool, nargs='?',
4727 default=True)
4728 with self.assertRaises(ArgumentParserError) as cm:
4729 parser.parse_args([])
4730 msg = str(cm.exception)
4731 self.assertRegex(msg, 'req_pos')
4732 self.assertRegex(msg, 'req_opt')
4733 self.assertNotIn(msg, 'opt_opt')
4734 with self.assertRaises(ArgumentParserError) as cm:
4735 parser.parse_args(['--req_opt=1'])
4736 msg = str(cm.exception)
4737 self.assertRegex(msg, 'req_pos')
4738 self.assertNotIn(msg, 'req_opt')
4739 self.assertNotIn(msg, 'opt_opt')
4740
4741 def test_optional_positional_not_in_message(self):
4742 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4743 parser.add_argument('req_pos')
4744 parser.add_argument('optional_positional', nargs='?', default='eggs')
4745 with self.assertRaises(ArgumentParserError) as cm:
4746 parser.parse_args([])
4747 msg = str(cm.exception)
4748 self.assertRegex(msg, 'req_pos')
4749 self.assertNotIn(msg, 'optional_positional')
4750
4751
R David Murray6fb8fb12012-08-31 22:45:20 -04004752# ================================================
4753# Check that the type function is called only once
4754# ================================================
4755
4756class TestTypeFunctionCallOnlyOnce(TestCase):
4757
4758 def test_type_function_call_only_once(self):
4759 def spam(string_to_convert):
4760 self.assertEqual(string_to_convert, 'spam!')
4761 return 'foo_converted'
4762
4763 parser = argparse.ArgumentParser()
4764 parser.add_argument('--foo', type=spam, default='bar')
4765 args = parser.parse_args('--foo spam!'.split())
4766 self.assertEqual(NS(foo='foo_converted'), args)
4767
Barry Warsaweaae1b72012-09-12 14:34:50 -04004768# ==================================================================
4769# Check semantics regarding the default argument and type conversion
4770# ==================================================================
R David Murray6fb8fb12012-08-31 22:45:20 -04004771
Barry Warsaweaae1b72012-09-12 14:34:50 -04004772class TestTypeFunctionCalledOnDefault(TestCase):
R David Murray6fb8fb12012-08-31 22:45:20 -04004773
4774 def test_type_function_call_with_non_string_default(self):
4775 def spam(int_to_convert):
4776 self.assertEqual(int_to_convert, 0)
4777 return 'foo_converted'
4778
4779 parser = argparse.ArgumentParser()
4780 parser.add_argument('--foo', type=spam, default=0)
4781 args = parser.parse_args([])
Barry Warsaweaae1b72012-09-12 14:34:50 -04004782 # foo should *not* be converted because its default is not a string.
4783 self.assertEqual(NS(foo=0), args)
4784
4785 def test_type_function_call_with_string_default(self):
4786 def spam(int_to_convert):
4787 return 'foo_converted'
4788
4789 parser = argparse.ArgumentParser()
4790 parser.add_argument('--foo', type=spam, default='0')
4791 args = parser.parse_args([])
4792 # foo is converted because its default is a string.
R David Murray6fb8fb12012-08-31 22:45:20 -04004793 self.assertEqual(NS(foo='foo_converted'), args)
4794
Barry Warsaweaae1b72012-09-12 14:34:50 -04004795 def test_no_double_type_conversion_of_default(self):
4796 def extend(str_to_convert):
4797 return str_to_convert + '*'
4798
4799 parser = argparse.ArgumentParser()
4800 parser.add_argument('--test', type=extend, default='*')
4801 args = parser.parse_args([])
4802 # The test argument will be two stars, one coming from the default
4803 # value and one coming from the type conversion being called exactly
4804 # once.
4805 self.assertEqual(NS(test='**'), args)
4806
Barry Warsaw4b2f9e92012-09-11 22:38:47 -04004807 def test_issue_15906(self):
4808 # Issue #15906: When action='append', type=str, default=[] are
4809 # providing, the dest value was the string representation "[]" when it
4810 # should have been an empty list.
4811 parser = argparse.ArgumentParser()
4812 parser.add_argument('--test', dest='test', type=str,
4813 default=[], action='append')
4814 args = parser.parse_args([])
4815 self.assertEqual(args.test, [])
4816
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004817# ======================
4818# parse_known_args tests
4819# ======================
4820
4821class TestParseKnownArgs(TestCase):
4822
R David Murrayb5228282012-09-08 12:08:01 -04004823 def test_arguments_tuple(self):
4824 parser = argparse.ArgumentParser()
4825 parser.parse_args(())
4826
4827 def test_arguments_list(self):
4828 parser = argparse.ArgumentParser()
4829 parser.parse_args([])
4830
4831 def test_arguments_tuple_positional(self):
4832 parser = argparse.ArgumentParser()
4833 parser.add_argument('x')
4834 parser.parse_args(('x',))
4835
4836 def test_arguments_list_positional(self):
4837 parser = argparse.ArgumentParser()
4838 parser.add_argument('x')
4839 parser.parse_args(['x'])
4840
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004841 def test_optionals(self):
4842 parser = argparse.ArgumentParser()
4843 parser.add_argument('--foo')
4844 args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
4845 self.assertEqual(NS(foo='F'), args)
4846 self.assertEqual(['--bar', '--baz'], extras)
4847
4848 def test_mixed(self):
4849 parser = argparse.ArgumentParser()
4850 parser.add_argument('-v', nargs='?', const=1, type=int)
4851 parser.add_argument('--spam', action='store_false')
4852 parser.add_argument('badger')
4853
4854 argv = ["B", "C", "--foo", "-v", "3", "4"]
4855 args, extras = parser.parse_known_args(argv)
4856 self.assertEqual(NS(v=3, spam=True, badger="B"), args)
4857 self.assertEqual(["C", "--foo", "4"], extras)
4858
R. David Murray0f6b9d22017-09-06 20:25:40 -04004859# ===========================
4860# parse_intermixed_args tests
4861# ===========================
4862
4863class TestIntermixedArgs(TestCase):
4864 def test_basic(self):
4865 # test parsing intermixed optionals and positionals
4866 parser = argparse.ArgumentParser(prog='PROG')
4867 parser.add_argument('--foo', dest='foo')
4868 bar = parser.add_argument('--bar', dest='bar', required=True)
4869 parser.add_argument('cmd')
4870 parser.add_argument('rest', nargs='*', type=int)
4871 argv = 'cmd --foo x 1 --bar y 2 3'.split()
4872 args = parser.parse_intermixed_args(argv)
4873 # rest gets [1,2,3] despite the foo and bar strings
4874 self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[1, 2, 3]), args)
4875
4876 args, extras = parser.parse_known_args(argv)
4877 # cannot parse the '1,2,3'
4878 self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[]), args)
4879 self.assertEqual(["1", "2", "3"], extras)
4880
4881 argv = 'cmd --foo x 1 --error 2 --bar y 3'.split()
4882 args, extras = parser.parse_known_intermixed_args(argv)
4883 # unknown optionals go into extras
4884 self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[1]), args)
4885 self.assertEqual(['--error', '2', '3'], extras)
4886
4887 # restores attributes that were temporarily changed
4888 self.assertIsNone(parser.usage)
4889 self.assertEqual(bar.required, True)
4890
4891 def test_remainder(self):
4892 # Intermixed and remainder are incompatible
4893 parser = ErrorRaisingArgumentParser(prog='PROG')
4894 parser.add_argument('-z')
4895 parser.add_argument('x')
4896 parser.add_argument('y', nargs='...')
4897 argv = 'X A B -z Z'.split()
4898 # intermixed fails with '...' (also 'A...')
4899 # self.assertRaises(TypeError, parser.parse_intermixed_args, argv)
4900 with self.assertRaises(TypeError) as cm:
4901 parser.parse_intermixed_args(argv)
4902 self.assertRegex(str(cm.exception), r'\.\.\.')
4903
4904 def test_exclusive(self):
4905 # mutually exclusive group; intermixed works fine
4906 parser = ErrorRaisingArgumentParser(prog='PROG')
4907 group = parser.add_mutually_exclusive_group(required=True)
4908 group.add_argument('--foo', action='store_true', help='FOO')
4909 group.add_argument('--spam', help='SPAM')
4910 parser.add_argument('badger', nargs='*', default='X', help='BADGER')
4911 args = parser.parse_intermixed_args('1 --foo 2'.split())
4912 self.assertEqual(NS(badger=['1', '2'], foo=True, spam=None), args)
4913 self.assertRaises(ArgumentParserError, parser.parse_intermixed_args, '1 2'.split())
4914 self.assertEqual(group.required, True)
4915
4916 def test_exclusive_incompatible(self):
4917 # mutually exclusive group including positional - fail
4918 parser = ErrorRaisingArgumentParser(prog='PROG')
4919 group = parser.add_mutually_exclusive_group(required=True)
4920 group.add_argument('--foo', action='store_true', help='FOO')
4921 group.add_argument('--spam', help='SPAM')
4922 group.add_argument('badger', nargs='*', default='X', help='BADGER')
4923 self.assertRaises(TypeError, parser.parse_intermixed_args, [])
4924 self.assertEqual(group.required, True)
4925
4926class TestIntermixedMessageContentError(TestCase):
4927 # case where Intermixed gives different error message
4928 # error is raised by 1st parsing step
4929 def test_missing_argument_name_in_message(self):
4930 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4931 parser.add_argument('req_pos', type=str)
4932 parser.add_argument('-req_opt', type=int, required=True)
4933
4934 with self.assertRaises(ArgumentParserError) as cm:
4935 parser.parse_args([])
4936 msg = str(cm.exception)
4937 self.assertRegex(msg, 'req_pos')
4938 self.assertRegex(msg, 'req_opt')
4939
4940 with self.assertRaises(ArgumentParserError) as cm:
4941 parser.parse_intermixed_args([])
4942 msg = str(cm.exception)
4943 self.assertNotRegex(msg, 'req_pos')
4944 self.assertRegex(msg, 'req_opt')
4945
Steven Bethard8d9a4622011-03-26 17:33:56 +01004946# ==========================
4947# add_argument metavar tests
4948# ==========================
4949
4950class TestAddArgumentMetavar(TestCase):
4951
4952 EXPECTED_MESSAGE = "length of metavar tuple does not match nargs"
4953
4954 def do_test_no_exception(self, nargs, metavar):
4955 parser = argparse.ArgumentParser()
4956 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4957
4958 def do_test_exception(self, nargs, metavar):
4959 parser = argparse.ArgumentParser()
4960 with self.assertRaises(ValueError) as cm:
4961 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4962 self.assertEqual(cm.exception.args[0], self.EXPECTED_MESSAGE)
4963
4964 # Unit tests for different values of metavar when nargs=None
4965
4966 def test_nargs_None_metavar_string(self):
4967 self.do_test_no_exception(nargs=None, metavar="1")
4968
4969 def test_nargs_None_metavar_length0(self):
4970 self.do_test_exception(nargs=None, metavar=tuple())
4971
4972 def test_nargs_None_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05004973 self.do_test_no_exception(nargs=None, metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01004974
4975 def test_nargs_None_metavar_length2(self):
4976 self.do_test_exception(nargs=None, metavar=("1", "2"))
4977
4978 def test_nargs_None_metavar_length3(self):
4979 self.do_test_exception(nargs=None, metavar=("1", "2", "3"))
4980
4981 # Unit tests for different values of metavar when nargs=?
4982
4983 def test_nargs_optional_metavar_string(self):
4984 self.do_test_no_exception(nargs="?", metavar="1")
4985
4986 def test_nargs_optional_metavar_length0(self):
4987 self.do_test_exception(nargs="?", metavar=tuple())
4988
4989 def test_nargs_optional_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05004990 self.do_test_no_exception(nargs="?", metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01004991
4992 def test_nargs_optional_metavar_length2(self):
4993 self.do_test_exception(nargs="?", metavar=("1", "2"))
4994
4995 def test_nargs_optional_metavar_length3(self):
4996 self.do_test_exception(nargs="?", metavar=("1", "2", "3"))
4997
4998 # Unit tests for different values of metavar when nargs=*
4999
5000 def test_nargs_zeroormore_metavar_string(self):
5001 self.do_test_no_exception(nargs="*", metavar="1")
5002
5003 def test_nargs_zeroormore_metavar_length0(self):
5004 self.do_test_exception(nargs="*", metavar=tuple())
5005
5006 def test_nargs_zeroormore_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005007 self.do_test_exception(nargs="*", metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005008
5009 def test_nargs_zeroormore_metavar_length2(self):
5010 self.do_test_no_exception(nargs="*", metavar=("1", "2"))
5011
5012 def test_nargs_zeroormore_metavar_length3(self):
5013 self.do_test_exception(nargs="*", metavar=("1", "2", "3"))
5014
5015 # Unit tests for different values of metavar when nargs=+
5016
5017 def test_nargs_oneormore_metavar_string(self):
5018 self.do_test_no_exception(nargs="+", metavar="1")
5019
5020 def test_nargs_oneormore_metavar_length0(self):
5021 self.do_test_exception(nargs="+", metavar=tuple())
5022
5023 def test_nargs_oneormore_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005024 self.do_test_exception(nargs="+", metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005025
5026 def test_nargs_oneormore_metavar_length2(self):
5027 self.do_test_no_exception(nargs="+", metavar=("1", "2"))
5028
5029 def test_nargs_oneormore_metavar_length3(self):
5030 self.do_test_exception(nargs="+", metavar=("1", "2", "3"))
5031
5032 # Unit tests for different values of metavar when nargs=...
5033
5034 def test_nargs_remainder_metavar_string(self):
5035 self.do_test_no_exception(nargs="...", metavar="1")
5036
5037 def test_nargs_remainder_metavar_length0(self):
5038 self.do_test_no_exception(nargs="...", metavar=tuple())
5039
5040 def test_nargs_remainder_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005041 self.do_test_no_exception(nargs="...", metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005042
5043 def test_nargs_remainder_metavar_length2(self):
5044 self.do_test_no_exception(nargs="...", metavar=("1", "2"))
5045
5046 def test_nargs_remainder_metavar_length3(self):
5047 self.do_test_no_exception(nargs="...", metavar=("1", "2", "3"))
5048
5049 # Unit tests for different values of metavar when nargs=A...
5050
5051 def test_nargs_parser_metavar_string(self):
5052 self.do_test_no_exception(nargs="A...", metavar="1")
5053
5054 def test_nargs_parser_metavar_length0(self):
5055 self.do_test_exception(nargs="A...", metavar=tuple())
5056
5057 def test_nargs_parser_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005058 self.do_test_no_exception(nargs="A...", metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005059
5060 def test_nargs_parser_metavar_length2(self):
5061 self.do_test_exception(nargs="A...", metavar=("1", "2"))
5062
5063 def test_nargs_parser_metavar_length3(self):
5064 self.do_test_exception(nargs="A...", metavar=("1", "2", "3"))
5065
5066 # Unit tests for different values of metavar when nargs=1
5067
5068 def test_nargs_1_metavar_string(self):
5069 self.do_test_no_exception(nargs=1, metavar="1")
5070
5071 def test_nargs_1_metavar_length0(self):
5072 self.do_test_exception(nargs=1, metavar=tuple())
5073
5074 def test_nargs_1_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005075 self.do_test_no_exception(nargs=1, metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005076
5077 def test_nargs_1_metavar_length2(self):
5078 self.do_test_exception(nargs=1, metavar=("1", "2"))
5079
5080 def test_nargs_1_metavar_length3(self):
5081 self.do_test_exception(nargs=1, metavar=("1", "2", "3"))
5082
5083 # Unit tests for different values of metavar when nargs=2
5084
5085 def test_nargs_2_metavar_string(self):
5086 self.do_test_no_exception(nargs=2, metavar="1")
5087
5088 def test_nargs_2_metavar_length0(self):
5089 self.do_test_exception(nargs=2, metavar=tuple())
5090
5091 def test_nargs_2_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005092 self.do_test_exception(nargs=2, metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005093
5094 def test_nargs_2_metavar_length2(self):
5095 self.do_test_no_exception(nargs=2, metavar=("1", "2"))
5096
5097 def test_nargs_2_metavar_length3(self):
5098 self.do_test_exception(nargs=2, metavar=("1", "2", "3"))
5099
5100 # Unit tests for different values of metavar when nargs=3
5101
5102 def test_nargs_3_metavar_string(self):
5103 self.do_test_no_exception(nargs=3, metavar="1")
5104
5105 def test_nargs_3_metavar_length0(self):
5106 self.do_test_exception(nargs=3, metavar=tuple())
5107
5108 def test_nargs_3_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005109 self.do_test_exception(nargs=3, metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005110
5111 def test_nargs_3_metavar_length2(self):
5112 self.do_test_exception(nargs=3, metavar=("1", "2"))
5113
5114 def test_nargs_3_metavar_length3(self):
5115 self.do_test_no_exception(nargs=3, metavar=("1", "2", "3"))
5116
Benjamin Peterson698a18a2010-03-02 22:34:37 +00005117# ============================
5118# from argparse import * tests
5119# ============================
5120
5121class TestImportStar(TestCase):
5122
5123 def test(self):
5124 for name in argparse.__all__:
5125 self.assertTrue(hasattr(argparse, name))
5126
Steven Bethard72c55382010-11-01 15:23:12 +00005127 def test_all_exports_everything_but_modules(self):
5128 items = [
5129 name
5130 for name, value in vars(argparse).items()
Éric Araujo12159152010-12-04 17:31:49 +00005131 if not (name.startswith("_") or name == 'ngettext')
Steven Bethard72c55382010-11-01 15:23:12 +00005132 if not inspect.ismodule(value)
5133 ]
5134 self.assertEqual(sorted(items), sorted(argparse.__all__))
5135
wim glenn66f02aa2018-06-08 05:12:49 -05005136
5137class TestWrappingMetavar(TestCase):
5138
5139 def setUp(self):
Berker Peksag74102c92018-07-25 18:23:44 +03005140 super().setUp()
wim glenn66f02aa2018-06-08 05:12:49 -05005141 self.parser = ErrorRaisingArgumentParser(
5142 'this_is_spammy_prog_with_a_long_name_sorry_about_the_name'
5143 )
5144 # this metavar was triggering library assertion errors due to usage
5145 # message formatting incorrectly splitting on the ] chars within
5146 metavar = '<http[s]://example:1234>'
5147 self.parser.add_argument('--proxy', metavar=metavar)
5148
5149 def test_help_with_metavar(self):
5150 help_text = self.parser.format_help()
5151 self.assertEqual(help_text, textwrap.dedent('''\
5152 usage: this_is_spammy_prog_with_a_long_name_sorry_about_the_name
5153 [-h] [--proxy <http[s]://example:1234>]
5154
5155 optional arguments:
5156 -h, --help show this help message and exit
5157 --proxy <http[s]://example:1234>
5158 '''))
5159
5160
Benjamin Peterson698a18a2010-03-02 22:34:37 +00005161def test_main():
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02005162 support.run_unittest(__name__)
Benjamin Peterson4fd181c2010-03-02 23:46:42 +00005163 # Remove global references to avoid looking like we have refleaks.
5164 RFile.seen = {}
5165 WFile.seen = set()
5166
Benjamin Peterson698a18a2010-03-02 22:34:37 +00005167
5168
5169if __name__ == '__main__':
5170 test_main()