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