blob: 0753a4b59652dd339e2546f473249db1359e4dbe [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
Miss Islington (bot)b1e4d1b2019-07-13 22:59:56 -0700788
Miss Islington (bot)e412cbb2020-02-18 03:14:07 -0800789class TestOptionalsDisallowLongAbbreviationPrefixChars(ParserTestCase):
790 """Disallowing abbreviations works with alternative prefix characters"""
791
792 parser_signature = Sig(prefix_chars='+', allow_abbrev=False)
793 argument_signatures = [
794 Sig('++foo'),
795 Sig('++foodle', action='store_true'),
796 Sig('++foonly'),
797 ]
798 failures = ['+foon 3', '++foon 3', '++food', '++food ++foo 2']
799 successes = [
800 ('', NS(foo=None, foodle=False, foonly=None)),
801 ('++foo 3', NS(foo='3', foodle=False, foonly=None)),
802 ('++foonly 7 ++foodle ++foo 2', NS(foo='2', foodle=True, foonly='7')),
803 ]
804
805
Miss Islington (bot)b1e4d1b2019-07-13 22:59:56 -0700806class TestDisallowLongAbbreviationAllowsShortGrouping(ParserTestCase):
807 """Do not allow abbreviations of long options at all"""
808
809 parser_signature = Sig(allow_abbrev=False)
810 argument_signatures = [
811 Sig('-r'),
812 Sig('-c', action='count'),
813 ]
814 failures = ['-r', '-c -r']
815 successes = [
816 ('', NS(r=None, c=None)),
817 ('-ra', NS(r='a', c=None)),
818 ('-rcc', NS(r='cc', c=None)),
819 ('-cc', NS(r=None, c=2)),
820 ('-cc -ra', NS(r='a', c=2)),
821 ('-ccrcc', NS(r='cc', c=2)),
822 ]
823
Miss Islington (bot)e412cbb2020-02-18 03:14:07 -0800824
825class TestDisallowLongAbbreviationAllowsShortGroupingPrefix(ParserTestCase):
826 """Short option grouping works with custom prefix and allow_abbrev=False"""
827
828 parser_signature = Sig(prefix_chars='+', allow_abbrev=False)
829 argument_signatures = [
830 Sig('+r'),
831 Sig('+c', action='count'),
832 ]
833 failures = ['+r', '+c +r']
834 successes = [
835 ('', NS(r=None, c=None)),
836 ('+ra', NS(r='a', c=None)),
837 ('+rcc', NS(r='cc', c=None)),
838 ('+cc', NS(r=None, c=2)),
839 ('+cc +ra', NS(r='a', c=2)),
840 ('+ccrcc', NS(r='cc', c=2)),
841 ]
842
843
Benjamin Peterson698a18a2010-03-02 22:34:37 +0000844# ================
845# Positional tests
846# ================
847
848class TestPositionalsNargsNone(ParserTestCase):
849 """Test a Positional that doesn't specify nargs"""
850
851 argument_signatures = [Sig('foo')]
852 failures = ['', '-x', 'a b']
853 successes = [
854 ('a', NS(foo='a')),
855 ]
856
857
858class TestPositionalsNargs1(ParserTestCase):
859 """Test a Positional that specifies an nargs of 1"""
860
861 argument_signatures = [Sig('foo', nargs=1)]
862 failures = ['', '-x', 'a b']
863 successes = [
864 ('a', NS(foo=['a'])),
865 ]
866
867
868class TestPositionalsNargs2(ParserTestCase):
869 """Test a Positional that specifies an nargs of 2"""
870
871 argument_signatures = [Sig('foo', nargs=2)]
872 failures = ['', 'a', '-x', 'a b c']
873 successes = [
874 ('a b', NS(foo=['a', 'b'])),
875 ]
876
877
878class TestPositionalsNargsZeroOrMore(ParserTestCase):
879 """Test a Positional that specifies unlimited nargs"""
880
881 argument_signatures = [Sig('foo', nargs='*')]
882 failures = ['-x']
883 successes = [
884 ('', NS(foo=[])),
885 ('a', NS(foo=['a'])),
886 ('a b', NS(foo=['a', 'b'])),
887 ]
888
889
890class TestPositionalsNargsZeroOrMoreDefault(ParserTestCase):
891 """Test a Positional that specifies unlimited nargs and a default"""
892
893 argument_signatures = [Sig('foo', nargs='*', default='bar')]
894 failures = ['-x']
895 successes = [
896 ('', NS(foo='bar')),
897 ('a', NS(foo=['a'])),
898 ('a b', NS(foo=['a', 'b'])),
899 ]
900
901
902class TestPositionalsNargsOneOrMore(ParserTestCase):
903 """Test a Positional that specifies one or more nargs"""
904
905 argument_signatures = [Sig('foo', nargs='+')]
906 failures = ['', '-x']
907 successes = [
908 ('a', NS(foo=['a'])),
909 ('a b', NS(foo=['a', 'b'])),
910 ]
911
912
913class TestPositionalsNargsOptional(ParserTestCase):
914 """Tests an Optional Positional"""
915
916 argument_signatures = [Sig('foo', nargs='?')]
917 failures = ['-x', 'a b']
918 successes = [
919 ('', NS(foo=None)),
920 ('a', NS(foo='a')),
921 ]
922
923
924class TestPositionalsNargsOptionalDefault(ParserTestCase):
925 """Tests an Optional Positional with a default value"""
926
927 argument_signatures = [Sig('foo', nargs='?', default=42)]
928 failures = ['-x', 'a b']
929 successes = [
930 ('', NS(foo=42)),
931 ('a', NS(foo='a')),
932 ]
933
934
935class TestPositionalsNargsOptionalConvertedDefault(ParserTestCase):
936 """Tests an Optional Positional with a default value
937 that needs to be converted to the appropriate type.
938 """
939
940 argument_signatures = [
941 Sig('foo', nargs='?', type=int, default='42'),
942 ]
943 failures = ['-x', 'a b', '1 2']
944 successes = [
945 ('', NS(foo=42)),
946 ('1', NS(foo=1)),
947 ]
948
949
950class TestPositionalsNargsNoneNone(ParserTestCase):
951 """Test two Positionals that don't specify nargs"""
952
953 argument_signatures = [Sig('foo'), Sig('bar')]
954 failures = ['', '-x', 'a', 'a b c']
955 successes = [
956 ('a b', NS(foo='a', bar='b')),
957 ]
958
959
960class TestPositionalsNargsNone1(ParserTestCase):
961 """Test a Positional with no nargs followed by one with 1"""
962
963 argument_signatures = [Sig('foo'), Sig('bar', nargs=1)]
964 failures = ['', '--foo', 'a', 'a b c']
965 successes = [
966 ('a b', NS(foo='a', bar=['b'])),
967 ]
968
969
970class TestPositionalsNargs2None(ParserTestCase):
971 """Test a Positional with 2 nargs followed by one with none"""
972
973 argument_signatures = [Sig('foo', nargs=2), Sig('bar')]
974 failures = ['', '--foo', 'a', 'a b', 'a b c d']
975 successes = [
976 ('a b c', NS(foo=['a', 'b'], bar='c')),
977 ]
978
979
980class TestPositionalsNargsNoneZeroOrMore(ParserTestCase):
981 """Test a Positional with no nargs followed by one with unlimited"""
982
983 argument_signatures = [Sig('foo'), Sig('bar', nargs='*')]
984 failures = ['', '--foo']
985 successes = [
986 ('a', NS(foo='a', bar=[])),
987 ('a b', NS(foo='a', bar=['b'])),
988 ('a b c', NS(foo='a', bar=['b', 'c'])),
989 ]
990
991
992class TestPositionalsNargsNoneOneOrMore(ParserTestCase):
993 """Test a Positional with no nargs followed by one with one or more"""
994
995 argument_signatures = [Sig('foo'), Sig('bar', nargs='+')]
996 failures = ['', '--foo', 'a']
997 successes = [
998 ('a b', NS(foo='a', bar=['b'])),
999 ('a b c', NS(foo='a', bar=['b', 'c'])),
1000 ]
1001
1002
1003class TestPositionalsNargsNoneOptional(ParserTestCase):
1004 """Test a Positional with no nargs followed by one with an Optional"""
1005
1006 argument_signatures = [Sig('foo'), Sig('bar', nargs='?')]
1007 failures = ['', '--foo', 'a b c']
1008 successes = [
1009 ('a', NS(foo='a', bar=None)),
1010 ('a b', NS(foo='a', bar='b')),
1011 ]
1012
1013
1014class TestPositionalsNargsZeroOrMoreNone(ParserTestCase):
1015 """Test a Positional with unlimited nargs followed by one with none"""
1016
1017 argument_signatures = [Sig('foo', nargs='*'), Sig('bar')]
1018 failures = ['', '--foo']
1019 successes = [
1020 ('a', NS(foo=[], bar='a')),
1021 ('a b', NS(foo=['a'], bar='b')),
1022 ('a b c', NS(foo=['a', 'b'], bar='c')),
1023 ]
1024
1025
1026class TestPositionalsNargsOneOrMoreNone(ParserTestCase):
1027 """Test a Positional with one or more nargs followed by one with none"""
1028
1029 argument_signatures = [Sig('foo', nargs='+'), Sig('bar')]
1030 failures = ['', '--foo', 'a']
1031 successes = [
1032 ('a b', NS(foo=['a'], bar='b')),
1033 ('a b c', NS(foo=['a', 'b'], bar='c')),
1034 ]
1035
1036
1037class TestPositionalsNargsOptionalNone(ParserTestCase):
1038 """Test a Positional with an Optional nargs followed by one with none"""
1039
1040 argument_signatures = [Sig('foo', nargs='?', default=42), Sig('bar')]
1041 failures = ['', '--foo', 'a b c']
1042 successes = [
1043 ('a', NS(foo=42, bar='a')),
1044 ('a b', NS(foo='a', bar='b')),
1045 ]
1046
1047
1048class TestPositionalsNargs2ZeroOrMore(ParserTestCase):
1049 """Test a Positional with 2 nargs followed by one with unlimited"""
1050
1051 argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='*')]
1052 failures = ['', '--foo', 'a']
1053 successes = [
1054 ('a b', NS(foo=['a', 'b'], bar=[])),
1055 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
1056 ]
1057
1058
1059class TestPositionalsNargs2OneOrMore(ParserTestCase):
1060 """Test a Positional with 2 nargs followed by one with one or more"""
1061
1062 argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='+')]
1063 failures = ['', '--foo', 'a', 'a b']
1064 successes = [
1065 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
1066 ]
1067
1068
1069class TestPositionalsNargs2Optional(ParserTestCase):
1070 """Test a Positional with 2 nargs followed by one optional"""
1071
1072 argument_signatures = [Sig('foo', nargs=2), Sig('bar', nargs='?')]
1073 failures = ['', '--foo', 'a', 'a b c d']
1074 successes = [
1075 ('a b', NS(foo=['a', 'b'], bar=None)),
1076 ('a b c', NS(foo=['a', 'b'], bar='c')),
1077 ]
1078
1079
1080class TestPositionalsNargsZeroOrMore1(ParserTestCase):
1081 """Test a Positional with unlimited nargs followed by one with 1"""
1082
1083 argument_signatures = [Sig('foo', nargs='*'), Sig('bar', nargs=1)]
1084 failures = ['', '--foo', ]
1085 successes = [
1086 ('a', NS(foo=[], bar=['a'])),
1087 ('a b', NS(foo=['a'], bar=['b'])),
1088 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
1089 ]
1090
1091
1092class TestPositionalsNargsOneOrMore1(ParserTestCase):
1093 """Test a Positional with one or more nargs followed by one with 1"""
1094
1095 argument_signatures = [Sig('foo', nargs='+'), Sig('bar', nargs=1)]
1096 failures = ['', '--foo', 'a']
1097 successes = [
1098 ('a b', NS(foo=['a'], bar=['b'])),
1099 ('a b c', NS(foo=['a', 'b'], bar=['c'])),
1100 ]
1101
1102
1103class TestPositionalsNargsOptional1(ParserTestCase):
1104 """Test a Positional with an Optional nargs followed by one with 1"""
1105
1106 argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs=1)]
1107 failures = ['', '--foo', 'a b c']
1108 successes = [
1109 ('a', NS(foo=None, bar=['a'])),
1110 ('a b', NS(foo='a', bar=['b'])),
1111 ]
1112
1113
1114class TestPositionalsNargsNoneZeroOrMore1(ParserTestCase):
1115 """Test three Positionals: no nargs, unlimited nargs and 1 nargs"""
1116
1117 argument_signatures = [
1118 Sig('foo'),
1119 Sig('bar', nargs='*'),
1120 Sig('baz', nargs=1),
1121 ]
1122 failures = ['', '--foo', 'a']
1123 successes = [
1124 ('a b', NS(foo='a', bar=[], baz=['b'])),
1125 ('a b c', NS(foo='a', bar=['b'], baz=['c'])),
1126 ]
1127
1128
1129class TestPositionalsNargsNoneOneOrMore1(ParserTestCase):
1130 """Test three Positionals: no nargs, one or more nargs and 1 nargs"""
1131
1132 argument_signatures = [
1133 Sig('foo'),
1134 Sig('bar', nargs='+'),
1135 Sig('baz', nargs=1),
1136 ]
1137 failures = ['', '--foo', 'a', 'b']
1138 successes = [
1139 ('a b c', NS(foo='a', bar=['b'], baz=['c'])),
1140 ('a b c d', NS(foo='a', bar=['b', 'c'], baz=['d'])),
1141 ]
1142
1143
1144class TestPositionalsNargsNoneOptional1(ParserTestCase):
1145 """Test three Positionals: no nargs, optional narg and 1 nargs"""
1146
1147 argument_signatures = [
1148 Sig('foo'),
1149 Sig('bar', nargs='?', default=0.625),
1150 Sig('baz', nargs=1),
1151 ]
1152 failures = ['', '--foo', 'a']
1153 successes = [
1154 ('a b', NS(foo='a', bar=0.625, baz=['b'])),
1155 ('a b c', NS(foo='a', bar='b', baz=['c'])),
1156 ]
1157
1158
1159class TestPositionalsNargsOptionalOptional(ParserTestCase):
1160 """Test two optional nargs"""
1161
1162 argument_signatures = [
1163 Sig('foo', nargs='?'),
1164 Sig('bar', nargs='?', default=42),
1165 ]
1166 failures = ['--foo', 'a b c']
1167 successes = [
1168 ('', NS(foo=None, bar=42)),
1169 ('a', NS(foo='a', bar=42)),
1170 ('a b', NS(foo='a', bar='b')),
1171 ]
1172
1173
1174class TestPositionalsNargsOptionalZeroOrMore(ParserTestCase):
1175 """Test an Optional narg followed by unlimited nargs"""
1176
1177 argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs='*')]
1178 failures = ['--foo']
1179 successes = [
1180 ('', NS(foo=None, bar=[])),
1181 ('a', NS(foo='a', bar=[])),
1182 ('a b', NS(foo='a', bar=['b'])),
1183 ('a b c', NS(foo='a', bar=['b', 'c'])),
1184 ]
1185
1186
1187class TestPositionalsNargsOptionalOneOrMore(ParserTestCase):
1188 """Test an Optional narg followed by one or more nargs"""
1189
1190 argument_signatures = [Sig('foo', nargs='?'), Sig('bar', nargs='+')]
1191 failures = ['', '--foo']
1192 successes = [
1193 ('a', NS(foo=None, bar=['a'])),
1194 ('a b', NS(foo='a', bar=['b'])),
1195 ('a b c', NS(foo='a', bar=['b', 'c'])),
1196 ]
1197
1198
1199class TestPositionalsChoicesString(ParserTestCase):
1200 """Test a set of single-character choices"""
1201
1202 argument_signatures = [Sig('spam', choices=set('abcdefg'))]
1203 failures = ['', '--foo', 'h', '42', 'ef']
1204 successes = [
1205 ('a', NS(spam='a')),
1206 ('g', NS(spam='g')),
1207 ]
1208
1209
1210class TestPositionalsChoicesInt(ParserTestCase):
1211 """Test a set of integer choices"""
1212
1213 argument_signatures = [Sig('spam', type=int, choices=range(20))]
1214 failures = ['', '--foo', 'h', '42', 'ef']
1215 successes = [
1216 ('4', NS(spam=4)),
1217 ('15', NS(spam=15)),
1218 ]
1219
1220
1221class TestPositionalsActionAppend(ParserTestCase):
1222 """Test the 'append' action"""
1223
1224 argument_signatures = [
1225 Sig('spam', action='append'),
1226 Sig('spam', action='append', nargs=2),
1227 ]
1228 failures = ['', '--foo', 'a', 'a b', 'a b c d']
1229 successes = [
1230 ('a b c', NS(spam=['a', ['b', 'c']])),
1231 ]
1232
1233# ========================================
1234# Combined optionals and positionals tests
1235# ========================================
1236
1237class TestOptionalsNumericAndPositionals(ParserTestCase):
1238 """Tests negative number args when numeric options are present"""
1239
1240 argument_signatures = [
1241 Sig('x', nargs='?'),
1242 Sig('-4', dest='y', action='store_true'),
1243 ]
1244 failures = ['-2', '-315']
1245 successes = [
1246 ('', NS(x=None, y=False)),
1247 ('a', NS(x='a', y=False)),
1248 ('-4', NS(x=None, y=True)),
1249 ('-4 a', NS(x='a', y=True)),
1250 ]
1251
1252
1253class TestOptionalsAlmostNumericAndPositionals(ParserTestCase):
1254 """Tests negative number args when almost numeric options are present"""
1255
1256 argument_signatures = [
1257 Sig('x', nargs='?'),
1258 Sig('-k4', dest='y', action='store_true'),
1259 ]
1260 failures = ['-k3']
1261 successes = [
1262 ('', NS(x=None, y=False)),
1263 ('-2', NS(x='-2', y=False)),
1264 ('a', NS(x='a', y=False)),
1265 ('-k4', NS(x=None, y=True)),
1266 ('-k4 a', NS(x='a', y=True)),
1267 ]
1268
1269
1270class TestEmptyAndSpaceContainingArguments(ParserTestCase):
1271
1272 argument_signatures = [
1273 Sig('x', nargs='?'),
1274 Sig('-y', '--yyy', dest='y'),
1275 ]
1276 failures = ['-y']
1277 successes = [
1278 ([''], NS(x='', y=None)),
1279 (['a badger'], NS(x='a badger', y=None)),
1280 (['-a badger'], NS(x='-a badger', y=None)),
1281 (['-y', ''], NS(x=None, y='')),
1282 (['-y', 'a badger'], NS(x=None, y='a badger')),
1283 (['-y', '-a badger'], NS(x=None, y='-a badger')),
1284 (['--yyy=a badger'], NS(x=None, y='a badger')),
1285 (['--yyy=-a badger'], NS(x=None, y='-a badger')),
1286 ]
1287
1288
1289class TestPrefixCharacterOnlyArguments(ParserTestCase):
1290
1291 parser_signature = Sig(prefix_chars='-+')
1292 argument_signatures = [
1293 Sig('-', dest='x', nargs='?', const='badger'),
1294 Sig('+', dest='y', type=int, default=42),
1295 Sig('-+-', dest='z', action='store_true'),
1296 ]
1297 failures = ['-y', '+ -']
1298 successes = [
1299 ('', NS(x=None, y=42, z=False)),
1300 ('-', NS(x='badger', y=42, z=False)),
1301 ('- X', NS(x='X', y=42, z=False)),
1302 ('+ -3', NS(x=None, y=-3, z=False)),
1303 ('-+-', NS(x=None, y=42, z=True)),
1304 ('- ===', NS(x='===', y=42, z=False)),
1305 ]
1306
1307
1308class TestNargsZeroOrMore(ParserTestCase):
Martin Pantercc71a792016-04-05 06:19:42 +00001309 """Tests specifying args for an Optional that accepts zero or more"""
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001310
1311 argument_signatures = [Sig('-x', nargs='*'), Sig('y', nargs='*')]
1312 failures = []
1313 successes = [
1314 ('', NS(x=None, y=[])),
1315 ('-x', NS(x=[], y=[])),
1316 ('-x a', NS(x=['a'], y=[])),
1317 ('-x a -- b', NS(x=['a'], y=['b'])),
1318 ('a', NS(x=None, y=['a'])),
1319 ('a -x', NS(x=[], y=['a'])),
1320 ('a -x b', NS(x=['b'], y=['a'])),
1321 ]
1322
1323
1324class TestNargsRemainder(ParserTestCase):
1325 """Tests specifying a positional with nargs=REMAINDER"""
1326
1327 argument_signatures = [Sig('x'), Sig('y', nargs='...'), Sig('-z')]
1328 failures = ['', '-z', '-z Z']
1329 successes = [
1330 ('X', NS(x='X', y=[], z=None)),
1331 ('-z Z X', NS(x='X', y=[], z='Z')),
1332 ('X A B -z Z', NS(x='X', y=['A', 'B', '-z', 'Z'], z=None)),
1333 ('X Y --foo', NS(x='X', y=['Y', '--foo'], z=None)),
1334 ]
1335
1336
1337class TestOptionLike(ParserTestCase):
1338 """Tests options that may or may not be arguments"""
1339
1340 argument_signatures = [
1341 Sig('-x', type=float),
1342 Sig('-3', type=float, dest='y'),
1343 Sig('z', nargs='*'),
1344 ]
1345 failures = ['-x', '-y2.5', '-xa', '-x -a',
1346 '-x -3', '-x -3.5', '-3 -3.5',
1347 '-x -2.5', '-x -2.5 a', '-3 -.5',
1348 'a x -1', '-x -1 a', '-3 -1 a']
1349 successes = [
1350 ('', NS(x=None, y=None, z=[])),
1351 ('-x 2.5', NS(x=2.5, y=None, z=[])),
1352 ('-x 2.5 a', NS(x=2.5, y=None, z=['a'])),
1353 ('-3.5', NS(x=None, y=0.5, z=[])),
1354 ('-3-.5', NS(x=None, y=-0.5, z=[])),
1355 ('-3 .5', NS(x=None, y=0.5, z=[])),
1356 ('a -3.5', NS(x=None, y=0.5, z=['a'])),
1357 ('a', NS(x=None, y=None, z=['a'])),
1358 ('a -x 1', NS(x=1.0, y=None, z=['a'])),
1359 ('-x 1 a', NS(x=1.0, y=None, z=['a'])),
1360 ('-3 1 a', NS(x=None, y=1.0, z=['a'])),
1361 ]
1362
1363
1364class TestDefaultSuppress(ParserTestCase):
1365 """Test actions with suppressed defaults"""
1366
1367 argument_signatures = [
1368 Sig('foo', nargs='?', default=argparse.SUPPRESS),
1369 Sig('bar', nargs='*', default=argparse.SUPPRESS),
1370 Sig('--baz', action='store_true', default=argparse.SUPPRESS),
1371 ]
1372 failures = ['-x']
1373 successes = [
1374 ('', NS()),
1375 ('a', NS(foo='a')),
1376 ('a b', NS(foo='a', bar=['b'])),
1377 ('--baz', NS(baz=True)),
1378 ('a --baz', NS(foo='a', baz=True)),
1379 ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
1380 ]
1381
1382
1383class TestParserDefaultSuppress(ParserTestCase):
1384 """Test actions with a parser-level default of SUPPRESS"""
1385
1386 parser_signature = Sig(argument_default=argparse.SUPPRESS)
1387 argument_signatures = [
1388 Sig('foo', nargs='?'),
1389 Sig('bar', nargs='*'),
1390 Sig('--baz', action='store_true'),
1391 ]
1392 failures = ['-x']
1393 successes = [
1394 ('', NS()),
1395 ('a', NS(foo='a')),
1396 ('a b', NS(foo='a', bar=['b'])),
1397 ('--baz', NS(baz=True)),
1398 ('a --baz', NS(foo='a', baz=True)),
1399 ('--baz a b', NS(foo='a', bar=['b'], baz=True)),
1400 ]
1401
1402
1403class TestParserDefault42(ParserTestCase):
1404 """Test actions with a parser-level default of 42"""
1405
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02001406 parser_signature = Sig(argument_default=42)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001407 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02001408 Sig('--version', action='version', version='1.0'),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001409 Sig('foo', nargs='?'),
1410 Sig('bar', nargs='*'),
1411 Sig('--baz', action='store_true'),
1412 ]
1413 failures = ['-x']
1414 successes = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02001415 ('', NS(foo=42, bar=42, baz=42, version=42)),
1416 ('a', NS(foo='a', bar=42, baz=42, version=42)),
1417 ('a b', NS(foo='a', bar=['b'], baz=42, version=42)),
1418 ('--baz', NS(foo=42, bar=42, baz=True, version=42)),
1419 ('a --baz', NS(foo='a', bar=42, baz=True, version=42)),
1420 ('--baz a b', NS(foo='a', bar=['b'], baz=True, version=42)),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001421 ]
1422
1423
1424class TestArgumentsFromFile(TempDirMixin, ParserTestCase):
1425 """Test reading arguments from a file"""
1426
1427 def setUp(self):
1428 super(TestArgumentsFromFile, self).setUp()
1429 file_texts = [
1430 ('hello', 'hello world!\n'),
1431 ('recursive', '-a\n'
1432 'A\n'
1433 '@hello'),
1434 ('invalid', '@no-such-path\n'),
1435 ]
1436 for path, text in file_texts:
Serhiy Storchaka5b10b982019-03-05 10:06:26 +02001437 with open(path, 'w') as file:
1438 file.write(text)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001439
1440 parser_signature = Sig(fromfile_prefix_chars='@')
1441 argument_signatures = [
1442 Sig('-a'),
1443 Sig('x'),
1444 Sig('y', nargs='+'),
1445 ]
1446 failures = ['', '-b', 'X', '@invalid', '@missing']
1447 successes = [
1448 ('X Y', NS(a=None, x='X', y=['Y'])),
1449 ('X -a A Y Z', NS(a='A', x='X', y=['Y', 'Z'])),
1450 ('@hello X', NS(a=None, x='hello world!', y=['X'])),
1451 ('X @hello', NS(a=None, x='X', y=['hello world!'])),
1452 ('-a B @recursive Y Z', NS(a='A', x='hello world!', y=['Y', 'Z'])),
1453 ('X @recursive Z -a B', NS(a='B', x='X', y=['hello world!', 'Z'])),
R David Murrayb94082a2012-07-21 22:20:11 -04001454 (["-a", "", "X", "Y"], NS(a='', x='X', y=['Y'])),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001455 ]
1456
1457
1458class TestArgumentsFromFileConverter(TempDirMixin, ParserTestCase):
1459 """Test reading arguments from a file"""
1460
1461 def setUp(self):
1462 super(TestArgumentsFromFileConverter, self).setUp()
1463 file_texts = [
1464 ('hello', 'hello world!\n'),
1465 ]
1466 for path, text in file_texts:
Serhiy Storchaka5b10b982019-03-05 10:06:26 +02001467 with open(path, 'w') as file:
1468 file.write(text)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001469
1470 class FromFileConverterArgumentParser(ErrorRaisingArgumentParser):
1471
1472 def convert_arg_line_to_args(self, arg_line):
1473 for arg in arg_line.split():
1474 if not arg.strip():
1475 continue
1476 yield arg
1477 parser_class = FromFileConverterArgumentParser
1478 parser_signature = Sig(fromfile_prefix_chars='@')
1479 argument_signatures = [
1480 Sig('y', nargs='+'),
1481 ]
1482 failures = []
1483 successes = [
1484 ('@hello X', NS(y=['hello', 'world!', 'X'])),
1485 ]
1486
1487
1488# =====================
1489# Type conversion tests
1490# =====================
1491
1492class TestFileTypeRepr(TestCase):
1493
1494 def test_r(self):
1495 type = argparse.FileType('r')
1496 self.assertEqual("FileType('r')", repr(type))
1497
1498 def test_wb_1(self):
1499 type = argparse.FileType('wb', 1)
1500 self.assertEqual("FileType('wb', 1)", repr(type))
1501
Petri Lehtinen74d6c252012-12-15 22:39:32 +02001502 def test_r_latin(self):
1503 type = argparse.FileType('r', encoding='latin_1')
1504 self.assertEqual("FileType('r', encoding='latin_1')", repr(type))
1505
1506 def test_w_big5_ignore(self):
1507 type = argparse.FileType('w', encoding='big5', errors='ignore')
1508 self.assertEqual("FileType('w', encoding='big5', errors='ignore')",
1509 repr(type))
1510
1511 def test_r_1_replace(self):
1512 type = argparse.FileType('r', 1, errors='replace')
1513 self.assertEqual("FileType('r', 1, errors='replace')", repr(type))
1514
Steve Dowerd0f49d22018-09-18 09:10:26 -07001515class StdStreamComparer:
1516 def __init__(self, attr):
1517 self.attr = attr
1518
1519 def __eq__(self, other):
1520 return other == getattr(sys, self.attr)
1521
1522eq_stdin = StdStreamComparer('stdin')
1523eq_stdout = StdStreamComparer('stdout')
1524eq_stderr = StdStreamComparer('stderr')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001525
1526class RFile(object):
1527 seen = {}
1528
1529 def __init__(self, name):
1530 self.name = name
1531
1532 def __eq__(self, other):
1533 if other in self.seen:
1534 text = self.seen[other]
1535 else:
1536 text = self.seen[other] = other.read()
1537 other.close()
1538 if not isinstance(text, str):
1539 text = text.decode('ascii')
1540 return self.name == other.name == text
1541
1542
1543class TestFileTypeR(TempDirMixin, ParserTestCase):
1544 """Test the FileType option/argument type for reading files"""
1545
1546 def setUp(self):
1547 super(TestFileTypeR, self).setUp()
1548 for file_name in ['foo', 'bar']:
Serhiy Storchaka5b10b982019-03-05 10:06:26 +02001549 with open(os.path.join(self.temp_dir, file_name), 'w') as file:
1550 file.write(file_name)
Steven Bethardb0270112011-01-24 21:02:50 +00001551 self.create_readonly_file('readonly')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001552
1553 argument_signatures = [
1554 Sig('-x', type=argparse.FileType()),
1555 Sig('spam', type=argparse.FileType('r')),
1556 ]
Steven Bethardb0270112011-01-24 21:02:50 +00001557 failures = ['-x', '', 'non-existent-file.txt']
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001558 successes = [
1559 ('foo', NS(x=None, spam=RFile('foo'))),
1560 ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
1561 ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
Steve Dowerd0f49d22018-09-18 09:10:26 -07001562 ('-x - -', NS(x=eq_stdin, spam=eq_stdin)),
Steven Bethardb0270112011-01-24 21:02:50 +00001563 ('readonly', NS(x=None, spam=RFile('readonly'))),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001564 ]
1565
R David Murray6fb8fb12012-08-31 22:45:20 -04001566class TestFileTypeDefaults(TempDirMixin, ParserTestCase):
1567 """Test that a file is not created unless the default is needed"""
1568 def setUp(self):
1569 super(TestFileTypeDefaults, self).setUp()
1570 file = open(os.path.join(self.temp_dir, 'good'), 'w')
1571 file.write('good')
1572 file.close()
1573
1574 argument_signatures = [
1575 Sig('-c', type=argparse.FileType('r'), default='no-file.txt'),
1576 ]
1577 # should provoke no such file error
1578 failures = ['']
1579 # should not provoke error because default file is created
1580 successes = [('-c good', NS(c=RFile('good')))]
1581
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001582
1583class TestFileTypeRB(TempDirMixin, ParserTestCase):
1584 """Test the FileType option/argument type for reading files"""
1585
1586 def setUp(self):
1587 super(TestFileTypeRB, self).setUp()
1588 for file_name in ['foo', 'bar']:
Serhiy Storchaka5b10b982019-03-05 10:06:26 +02001589 with open(os.path.join(self.temp_dir, file_name), 'w') as file:
1590 file.write(file_name)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001591
1592 argument_signatures = [
1593 Sig('-x', type=argparse.FileType('rb')),
1594 Sig('spam', type=argparse.FileType('rb')),
1595 ]
1596 failures = ['-x', '']
1597 successes = [
1598 ('foo', NS(x=None, spam=RFile('foo'))),
1599 ('-x foo bar', NS(x=RFile('foo'), spam=RFile('bar'))),
1600 ('bar -x foo', NS(x=RFile('foo'), spam=RFile('bar'))),
Steve Dowerd0f49d22018-09-18 09:10:26 -07001601 ('-x - -', NS(x=eq_stdin, spam=eq_stdin)),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001602 ]
1603
1604
1605class WFile(object):
1606 seen = set()
1607
1608 def __init__(self, name):
1609 self.name = name
1610
1611 def __eq__(self, other):
1612 if other not in self.seen:
1613 text = 'Check that file is writable.'
1614 if 'b' in other.mode:
1615 text = text.encode('ascii')
1616 other.write(text)
1617 other.close()
1618 self.seen.add(other)
1619 return self.name == other.name
1620
1621
Victor Stinnera04b39b2011-11-20 23:09:09 +01001622@unittest.skipIf(hasattr(os, 'geteuid') and os.geteuid() == 0,
1623 "non-root user required")
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001624class TestFileTypeW(TempDirMixin, ParserTestCase):
1625 """Test the FileType option/argument type for writing files"""
1626
Steven Bethardb0270112011-01-24 21:02:50 +00001627 def setUp(self):
1628 super(TestFileTypeW, self).setUp()
1629 self.create_readonly_file('readonly')
1630
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001631 argument_signatures = [
1632 Sig('-x', type=argparse.FileType('w')),
1633 Sig('spam', type=argparse.FileType('w')),
1634 ]
Steven Bethardb0270112011-01-24 21:02:50 +00001635 failures = ['-x', '', 'readonly']
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001636 successes = [
1637 ('foo', NS(x=None, spam=WFile('foo'))),
1638 ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
1639 ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
Steve Dowerd0f49d22018-09-18 09:10:26 -07001640 ('-x - -', NS(x=eq_stdout, spam=eq_stdout)),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001641 ]
1642
1643
1644class TestFileTypeWB(TempDirMixin, ParserTestCase):
1645
1646 argument_signatures = [
1647 Sig('-x', type=argparse.FileType('wb')),
1648 Sig('spam', type=argparse.FileType('wb')),
1649 ]
1650 failures = ['-x', '']
1651 successes = [
1652 ('foo', NS(x=None, spam=WFile('foo'))),
1653 ('-x foo bar', NS(x=WFile('foo'), spam=WFile('bar'))),
1654 ('bar -x foo', NS(x=WFile('foo'), spam=WFile('bar'))),
Steve Dowerd0f49d22018-09-18 09:10:26 -07001655 ('-x - -', NS(x=eq_stdout, spam=eq_stdout)),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001656 ]
1657
1658
Petri Lehtinen74d6c252012-12-15 22:39:32 +02001659class TestFileTypeOpenArgs(TestCase):
1660 """Test that open (the builtin) is correctly called"""
1661
1662 def test_open_args(self):
1663 FT = argparse.FileType
1664 cases = [
1665 (FT('rb'), ('rb', -1, None, None)),
1666 (FT('w', 1), ('w', 1, None, None)),
1667 (FT('w', errors='replace'), ('w', -1, None, 'replace')),
1668 (FT('wb', encoding='big5'), ('wb', -1, 'big5', None)),
1669 (FT('w', 0, 'l1', 'strict'), ('w', 0, 'l1', 'strict')),
1670 ]
1671 with mock.patch('builtins.open') as m:
1672 for type, args in cases:
1673 type('foo')
1674 m.assert_called_with('foo', *args)
1675
1676
Miss Islington (bot)606ac582019-06-07 14:11:59 -07001677class TestFileTypeMissingInitialization(TestCase):
1678 """
1679 Test that add_argument throws an error if FileType class
1680 object was passed instead of instance of FileType
1681 """
1682
1683 def test(self):
1684 parser = argparse.ArgumentParser()
1685 with self.assertRaises(ValueError) as cm:
1686 parser.add_argument('-x', type=argparse.FileType)
1687
1688 self.assertEqual(
1689 '%r is a FileType class object, instance of it must be passed'
1690 % (argparse.FileType,),
1691 str(cm.exception)
1692 )
1693
1694
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001695class TestTypeCallable(ParserTestCase):
1696 """Test some callables as option/argument types"""
1697
1698 argument_signatures = [
1699 Sig('--eggs', type=complex),
1700 Sig('spam', type=float),
1701 ]
1702 failures = ['a', '42j', '--eggs a', '--eggs 2i']
1703 successes = [
1704 ('--eggs=42 42', NS(eggs=42, spam=42.0)),
1705 ('--eggs 2j -- -1.5', NS(eggs=2j, spam=-1.5)),
1706 ('1024.675', NS(eggs=None, spam=1024.675)),
1707 ]
1708
1709
1710class TestTypeUserDefined(ParserTestCase):
1711 """Test a user-defined option/argument type"""
1712
1713 class MyType(TestCase):
1714
1715 def __init__(self, value):
1716 self.value = value
1717
1718 def __eq__(self, other):
1719 return (type(self), self.value) == (type(other), other.value)
1720
1721 argument_signatures = [
1722 Sig('-x', type=MyType),
1723 Sig('spam', type=MyType),
1724 ]
1725 failures = []
1726 successes = [
1727 ('a -x b', NS(x=MyType('b'), spam=MyType('a'))),
1728 ('-xf g', NS(x=MyType('f'), spam=MyType('g'))),
1729 ]
1730
1731
1732class TestTypeClassicClass(ParserTestCase):
1733 """Test a classic class type"""
1734
1735 class C:
1736
1737 def __init__(self, value):
1738 self.value = value
1739
1740 def __eq__(self, other):
1741 return (type(self), self.value) == (type(other), other.value)
1742
1743 argument_signatures = [
1744 Sig('-x', type=C),
1745 Sig('spam', type=C),
1746 ]
1747 failures = []
1748 successes = [
1749 ('a -x b', NS(x=C('b'), spam=C('a'))),
1750 ('-xf g', NS(x=C('f'), spam=C('g'))),
1751 ]
1752
1753
1754class TestTypeRegistration(TestCase):
1755 """Test a user-defined type by registering it"""
1756
1757 def test(self):
1758
1759 def get_my_type(string):
1760 return 'my_type{%s}' % string
1761
1762 parser = argparse.ArgumentParser()
1763 parser.register('type', 'my_type', get_my_type)
1764 parser.add_argument('-x', type='my_type')
1765 parser.add_argument('y', type='my_type')
1766
1767 self.assertEqual(parser.parse_args('1'.split()),
1768 NS(x=None, y='my_type{1}'))
1769 self.assertEqual(parser.parse_args('-x 1 42'.split()),
1770 NS(x='my_type{1}', y='my_type{42}'))
1771
1772
1773# ============
1774# Action tests
1775# ============
1776
1777class TestActionUserDefined(ParserTestCase):
1778 """Test a user-defined option/argument action"""
1779
1780 class OptionalAction(argparse.Action):
1781
1782 def __call__(self, parser, namespace, value, option_string=None):
1783 try:
1784 # check destination and option string
1785 assert self.dest == 'spam', 'dest: %s' % self.dest
1786 assert option_string == '-s', 'flag: %s' % option_string
1787 # when option is before argument, badger=2, and when
1788 # option is after argument, badger=<whatever was set>
1789 expected_ns = NS(spam=0.25)
1790 if value in [0.125, 0.625]:
1791 expected_ns.badger = 2
1792 elif value in [2.0]:
1793 expected_ns.badger = 84
1794 else:
1795 raise AssertionError('value: %s' % value)
1796 assert expected_ns == namespace, ('expected %s, got %s' %
1797 (expected_ns, namespace))
1798 except AssertionError:
1799 e = sys.exc_info()[1]
1800 raise ArgumentParserError('opt_action failed: %s' % e)
1801 setattr(namespace, 'spam', value)
1802
1803 class PositionalAction(argparse.Action):
1804
1805 def __call__(self, parser, namespace, value, option_string=None):
1806 try:
1807 assert option_string is None, ('option_string: %s' %
1808 option_string)
1809 # check destination
1810 assert self.dest == 'badger', 'dest: %s' % self.dest
1811 # when argument is before option, spam=0.25, and when
1812 # option is after argument, spam=<whatever was set>
1813 expected_ns = NS(badger=2)
1814 if value in [42, 84]:
1815 expected_ns.spam = 0.25
1816 elif value in [1]:
1817 expected_ns.spam = 0.625
1818 elif value in [2]:
1819 expected_ns.spam = 0.125
1820 else:
1821 raise AssertionError('value: %s' % value)
1822 assert expected_ns == namespace, ('expected %s, got %s' %
1823 (expected_ns, namespace))
1824 except AssertionError:
1825 e = sys.exc_info()[1]
1826 raise ArgumentParserError('arg_action failed: %s' % e)
1827 setattr(namespace, 'badger', value)
1828
1829 argument_signatures = [
1830 Sig('-s', dest='spam', action=OptionalAction,
1831 type=float, default=0.25),
1832 Sig('badger', action=PositionalAction,
1833 type=int, nargs='?', default=2),
1834 ]
1835 failures = []
1836 successes = [
1837 ('-s0.125', NS(spam=0.125, badger=2)),
1838 ('42', NS(spam=0.25, badger=42)),
1839 ('-s 0.625 1', NS(spam=0.625, badger=1)),
1840 ('84 -s2', NS(spam=2.0, badger=84)),
1841 ]
1842
1843
1844class TestActionRegistration(TestCase):
1845 """Test a user-defined action supplied by registering it"""
1846
1847 class MyAction(argparse.Action):
1848
1849 def __call__(self, parser, namespace, values, option_string=None):
1850 setattr(namespace, self.dest, 'foo[%s]' % values)
1851
1852 def test(self):
1853
1854 parser = argparse.ArgumentParser()
1855 parser.register('action', 'my_action', self.MyAction)
1856 parser.add_argument('badger', action='my_action')
1857
1858 self.assertEqual(parser.parse_args(['1']), NS(badger='foo[1]'))
1859 self.assertEqual(parser.parse_args(['42']), NS(badger='foo[42]'))
1860
1861
Batuhan Taşkayaaa32a7e2019-05-21 20:47:42 +03001862class TestActionExtend(ParserTestCase):
1863 argument_signatures = [
1864 Sig('--foo', action="extend", nargs="+", type=str),
1865 ]
1866 failures = ()
1867 successes = [
1868 ('--foo f1 --foo f2 f3 f4', NS(foo=['f1', 'f2', 'f3', 'f4'])),
1869 ]
1870
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001871# ================
1872# Subparsers tests
1873# ================
1874
1875class TestAddSubparsers(TestCase):
1876 """Test the add_subparsers method"""
1877
1878 def assertArgumentParserError(self, *args, **kwargs):
1879 self.assertRaises(ArgumentParserError, *args, **kwargs)
1880
Steven Bethardfd311a72010-12-18 11:19:23 +00001881 def _get_parser(self, subparser_help=False, prefix_chars=None,
1882 aliases=False):
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001883 # create a parser with a subparsers argument
R. David Murray88c49fe2010-08-03 17:56:09 +00001884 if prefix_chars:
1885 parser = ErrorRaisingArgumentParser(
1886 prog='PROG', description='main description', prefix_chars=prefix_chars)
1887 parser.add_argument(
1888 prefix_chars[0] * 2 + 'foo', action='store_true', help='foo help')
1889 else:
1890 parser = ErrorRaisingArgumentParser(
1891 prog='PROG', description='main description')
1892 parser.add_argument(
1893 '--foo', action='store_true', help='foo help')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001894 parser.add_argument(
1895 'bar', type=float, help='bar help')
1896
1897 # check that only one subparsers argument can be added
Anthony Sottileaaf6fc02017-09-20 14:35:27 -07001898 subparsers_kwargs = {'required': False}
Steven Bethardfd311a72010-12-18 11:19:23 +00001899 if aliases:
1900 subparsers_kwargs['metavar'] = 'COMMAND'
1901 subparsers_kwargs['title'] = 'commands'
1902 else:
1903 subparsers_kwargs['help'] = 'command help'
1904 subparsers = parser.add_subparsers(**subparsers_kwargs)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001905 self.assertArgumentParserError(parser.add_subparsers)
1906
1907 # add first sub-parser
1908 parser1_kwargs = dict(description='1 description')
1909 if subparser_help:
1910 parser1_kwargs['help'] = '1 help'
Steven Bethardfd311a72010-12-18 11:19:23 +00001911 if aliases:
1912 parser1_kwargs['aliases'] = ['1alias1', '1alias2']
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001913 parser1 = subparsers.add_parser('1', **parser1_kwargs)
1914 parser1.add_argument('-w', type=int, help='w help')
1915 parser1.add_argument('x', choices='abc', help='x help')
1916
1917 # add second sub-parser
1918 parser2_kwargs = dict(description='2 description')
1919 if subparser_help:
1920 parser2_kwargs['help'] = '2 help'
1921 parser2 = subparsers.add_parser('2', **parser2_kwargs)
1922 parser2.add_argument('-y', choices='123', help='y help')
1923 parser2.add_argument('z', type=complex, nargs='*', help='z help')
1924
R David Murray00528e82012-07-21 22:48:35 -04001925 # add third sub-parser
1926 parser3_kwargs = dict(description='3 description')
1927 if subparser_help:
1928 parser3_kwargs['help'] = '3 help'
1929 parser3 = subparsers.add_parser('3', **parser3_kwargs)
1930 parser3.add_argument('t', type=int, help='t help')
1931 parser3.add_argument('u', nargs='...', help='u help')
1932
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001933 # return the main parser
1934 return parser
1935
1936 def setUp(self):
Steven Bethard1f1c2472010-11-01 13:56:09 +00001937 super().setUp()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001938 self.parser = self._get_parser()
1939 self.command_help_parser = self._get_parser(subparser_help=True)
1940
1941 def test_parse_args_failures(self):
1942 # check some failure cases:
1943 for args_str in ['', 'a', 'a a', '0.5 a', '0.5 1',
1944 '0.5 1 -y', '0.5 2 -w']:
1945 args = args_str.split()
1946 self.assertArgumentParserError(self.parser.parse_args, args)
1947
1948 def test_parse_args(self):
1949 # check some non-failure cases:
1950 self.assertEqual(
1951 self.parser.parse_args('0.5 1 b -w 7'.split()),
1952 NS(foo=False, bar=0.5, w=7, x='b'),
1953 )
1954 self.assertEqual(
1955 self.parser.parse_args('0.25 --foo 2 -y 2 3j -- -1j'.split()),
1956 NS(foo=True, bar=0.25, y='2', z=[3j, -1j]),
1957 )
1958 self.assertEqual(
1959 self.parser.parse_args('--foo 0.125 1 c'.split()),
1960 NS(foo=True, bar=0.125, w=None, x='c'),
1961 )
R David Murray00528e82012-07-21 22:48:35 -04001962 self.assertEqual(
1963 self.parser.parse_args('-1.5 3 11 -- a --foo 7 -- b'.split()),
1964 NS(foo=False, bar=-1.5, t=11, u=['a', '--foo', '7', '--', 'b']),
1965 )
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001966
Steven Bethardfca2e8a2010-11-02 12:47:22 +00001967 def test_parse_known_args(self):
1968 self.assertEqual(
1969 self.parser.parse_known_args('0.5 1 b -w 7'.split()),
1970 (NS(foo=False, bar=0.5, w=7, x='b'), []),
1971 )
1972 self.assertEqual(
1973 self.parser.parse_known_args('0.5 -p 1 b -w 7'.split()),
1974 (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
1975 )
1976 self.assertEqual(
1977 self.parser.parse_known_args('0.5 1 b -w 7 -p'.split()),
1978 (NS(foo=False, bar=0.5, w=7, x='b'), ['-p']),
1979 )
1980 self.assertEqual(
1981 self.parser.parse_known_args('0.5 1 b -q -rs -w 7'.split()),
1982 (NS(foo=False, bar=0.5, w=7, x='b'), ['-q', '-rs']),
1983 )
1984 self.assertEqual(
1985 self.parser.parse_known_args('0.5 -W 1 b -X Y -w 7 Z'.split()),
1986 (NS(foo=False, bar=0.5, w=7, x='b'), ['-W', '-X', 'Y', 'Z']),
1987 )
1988
Benjamin Peterson698a18a2010-03-02 22:34:37 +00001989 def test_dest(self):
1990 parser = ErrorRaisingArgumentParser()
1991 parser.add_argument('--foo', action='store_true')
1992 subparsers = parser.add_subparsers(dest='bar')
1993 parser1 = subparsers.add_parser('1')
1994 parser1.add_argument('baz')
1995 self.assertEqual(NS(foo=False, bar='1', baz='2'),
1996 parser.parse_args('1 2'.split()))
1997
Anthony Sottileaaf6fc02017-09-20 14:35:27 -07001998 def _test_required_subparsers(self, parser):
1999 # Should parse the sub command
2000 ret = parser.parse_args(['run'])
2001 self.assertEqual(ret.command, 'run')
2002
2003 # Error when the command is missing
2004 self.assertArgumentParserError(parser.parse_args, ())
2005
2006 def test_required_subparsers_via_attribute(self):
2007 parser = ErrorRaisingArgumentParser()
2008 subparsers = parser.add_subparsers(dest='command')
2009 subparsers.required = True
2010 subparsers.add_parser('run')
2011 self._test_required_subparsers(parser)
2012
2013 def test_required_subparsers_via_kwarg(self):
2014 parser = ErrorRaisingArgumentParser()
2015 subparsers = parser.add_subparsers(dest='command', required=True)
2016 subparsers.add_parser('run')
2017 self._test_required_subparsers(parser)
2018
2019 def test_required_subparsers_default(self):
2020 parser = ErrorRaisingArgumentParser()
2021 subparsers = parser.add_subparsers(dest='command')
2022 subparsers.add_parser('run')
Ned Deily8ebf5ce2018-05-23 21:55:15 -04002023 # No error here
2024 ret = parser.parse_args(())
2025 self.assertIsNone(ret.command)
Anthony Sottileaaf6fc02017-09-20 14:35:27 -07002026
2027 def test_optional_subparsers(self):
2028 parser = ErrorRaisingArgumentParser()
2029 subparsers = parser.add_subparsers(dest='command', required=False)
2030 subparsers.add_parser('run')
2031 # No error here
2032 ret = parser.parse_args(())
2033 self.assertIsNone(ret.command)
2034
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002035 def test_help(self):
2036 self.assertEqual(self.parser.format_usage(),
Vinay Sajip9ae50502016-08-23 08:43:16 +01002037 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002038 self.assertEqual(self.parser.format_help(), textwrap.dedent('''\
Vinay Sajip9ae50502016-08-23 08:43:16 +01002039 usage: PROG [-h] [--foo] bar {1,2,3} ...
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002040
2041 main description
2042
2043 positional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01002044 bar bar help
2045 {1,2,3} command help
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002046
2047 optional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01002048 -h, --help show this help message and exit
2049 --foo foo help
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002050 '''))
2051
R. David Murray88c49fe2010-08-03 17:56:09 +00002052 def test_help_extra_prefix_chars(self):
2053 # Make sure - is still used for help if it is a non-first prefix char
2054 parser = self._get_parser(prefix_chars='+:-')
2055 self.assertEqual(parser.format_usage(),
Vinay Sajip9ae50502016-08-23 08:43:16 +01002056 'usage: PROG [-h] [++foo] bar {1,2,3} ...\n')
R. David Murray88c49fe2010-08-03 17:56:09 +00002057 self.assertEqual(parser.format_help(), textwrap.dedent('''\
Vinay Sajip9ae50502016-08-23 08:43:16 +01002058 usage: PROG [-h] [++foo] bar {1,2,3} ...
R. David Murray88c49fe2010-08-03 17:56:09 +00002059
2060 main description
2061
2062 positional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01002063 bar bar help
2064 {1,2,3} command help
R. David Murray88c49fe2010-08-03 17:56:09 +00002065
2066 optional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01002067 -h, --help show this help message and exit
2068 ++foo foo help
R. David Murray88c49fe2010-08-03 17:56:09 +00002069 '''))
2070
Xiang Zhang7fe28ad2017-01-22 14:37:22 +08002071 def test_help_non_breaking_spaces(self):
2072 parser = ErrorRaisingArgumentParser(
2073 prog='PROG', description='main description')
2074 parser.add_argument(
2075 "--non-breaking", action='store_false',
2076 help='help message containing non-breaking spaces shall not '
2077 'wrap\N{NO-BREAK SPACE}at non-breaking spaces')
2078 self.assertEqual(parser.format_help(), textwrap.dedent('''\
2079 usage: PROG [-h] [--non-breaking]
2080
2081 main description
2082
2083 optional arguments:
2084 -h, --help show this help message and exit
2085 --non-breaking help message containing non-breaking spaces shall not
2086 wrap\N{NO-BREAK SPACE}at non-breaking spaces
2087 '''))
R. David Murray88c49fe2010-08-03 17:56:09 +00002088
2089 def test_help_alternate_prefix_chars(self):
2090 parser = self._get_parser(prefix_chars='+:/')
2091 self.assertEqual(parser.format_usage(),
Vinay Sajip9ae50502016-08-23 08:43:16 +01002092 'usage: PROG [+h] [++foo] bar {1,2,3} ...\n')
R. David Murray88c49fe2010-08-03 17:56:09 +00002093 self.assertEqual(parser.format_help(), textwrap.dedent('''\
Vinay Sajip9ae50502016-08-23 08:43:16 +01002094 usage: PROG [+h] [++foo] bar {1,2,3} ...
R. David Murray88c49fe2010-08-03 17:56:09 +00002095
2096 main description
2097
2098 positional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01002099 bar bar help
2100 {1,2,3} command help
R. David Murray88c49fe2010-08-03 17:56:09 +00002101
2102 optional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01002103 +h, ++help show this help message and exit
2104 ++foo foo help
R. David Murray88c49fe2010-08-03 17:56:09 +00002105 '''))
2106
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002107 def test_parser_command_help(self):
2108 self.assertEqual(self.command_help_parser.format_usage(),
Vinay Sajip9ae50502016-08-23 08:43:16 +01002109 'usage: PROG [-h] [--foo] bar {1,2,3} ...\n')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002110 self.assertEqual(self.command_help_parser.format_help(),
2111 textwrap.dedent('''\
Vinay Sajip9ae50502016-08-23 08:43:16 +01002112 usage: PROG [-h] [--foo] bar {1,2,3} ...
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002113
2114 main description
2115
2116 positional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01002117 bar bar help
2118 {1,2,3} command help
2119 1 1 help
2120 2 2 help
2121 3 3 help
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002122
2123 optional arguments:
Vinay Sajip9ae50502016-08-23 08:43:16 +01002124 -h, --help show this help message and exit
2125 --foo foo help
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002126 '''))
2127
2128 def test_subparser_title_help(self):
2129 parser = ErrorRaisingArgumentParser(prog='PROG',
2130 description='main description')
2131 parser.add_argument('--foo', action='store_true', help='foo help')
2132 parser.add_argument('bar', help='bar help')
2133 subparsers = parser.add_subparsers(title='subcommands',
2134 description='command help',
2135 help='additional text')
2136 parser1 = subparsers.add_parser('1')
2137 parser2 = subparsers.add_parser('2')
2138 self.assertEqual(parser.format_usage(),
2139 'usage: PROG [-h] [--foo] bar {1,2} ...\n')
2140 self.assertEqual(parser.format_help(), textwrap.dedent('''\
2141 usage: PROG [-h] [--foo] bar {1,2} ...
2142
2143 main description
2144
2145 positional arguments:
2146 bar bar help
2147
2148 optional arguments:
2149 -h, --help show this help message and exit
2150 --foo foo help
2151
2152 subcommands:
2153 command help
2154
2155 {1,2} additional text
2156 '''))
2157
2158 def _test_subparser_help(self, args_str, expected_help):
Berker Peksag1c5f56a2014-07-06 09:33:20 +03002159 with self.assertRaises(ArgumentParserError) as cm:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002160 self.parser.parse_args(args_str.split())
Berker Peksag1c5f56a2014-07-06 09:33:20 +03002161 self.assertEqual(expected_help, cm.exception.stdout)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002162
2163 def test_subparser1_help(self):
2164 self._test_subparser_help('5.0 1 -h', textwrap.dedent('''\
2165 usage: PROG bar 1 [-h] [-w W] {a,b,c}
2166
2167 1 description
2168
2169 positional arguments:
2170 {a,b,c} x help
2171
2172 optional arguments:
2173 -h, --help show this help message and exit
2174 -w W w help
2175 '''))
2176
2177 def test_subparser2_help(self):
2178 self._test_subparser_help('5.0 2 -h', textwrap.dedent('''\
2179 usage: PROG bar 2 [-h] [-y {1,2,3}] [z [z ...]]
2180
2181 2 description
2182
2183 positional arguments:
2184 z z help
2185
2186 optional arguments:
2187 -h, --help show this help message and exit
2188 -y {1,2,3} y help
2189 '''))
2190
Steven Bethardfd311a72010-12-18 11:19:23 +00002191 def test_alias_invocation(self):
2192 parser = self._get_parser(aliases=True)
2193 self.assertEqual(
2194 parser.parse_known_args('0.5 1alias1 b'.split()),
2195 (NS(foo=False, bar=0.5, w=None, x='b'), []),
2196 )
2197 self.assertEqual(
2198 parser.parse_known_args('0.5 1alias2 b'.split()),
2199 (NS(foo=False, bar=0.5, w=None, x='b'), []),
2200 )
2201
2202 def test_error_alias_invocation(self):
2203 parser = self._get_parser(aliases=True)
2204 self.assertArgumentParserError(parser.parse_args,
2205 '0.5 1alias3 b'.split())
2206
2207 def test_alias_help(self):
2208 parser = self._get_parser(aliases=True, subparser_help=True)
2209 self.maxDiff = None
2210 self.assertEqual(parser.format_help(), textwrap.dedent("""\
2211 usage: PROG [-h] [--foo] bar COMMAND ...
2212
2213 main description
2214
2215 positional arguments:
2216 bar bar help
2217
2218 optional arguments:
2219 -h, --help show this help message and exit
2220 --foo foo help
2221
2222 commands:
2223 COMMAND
2224 1 (1alias1, 1alias2)
2225 1 help
2226 2 2 help
R David Murray00528e82012-07-21 22:48:35 -04002227 3 3 help
Steven Bethardfd311a72010-12-18 11:19:23 +00002228 """))
2229
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002230# ============
2231# Groups tests
2232# ============
2233
2234class TestPositionalsGroups(TestCase):
2235 """Tests that order of group positionals matches construction order"""
2236
2237 def test_nongroup_first(self):
2238 parser = ErrorRaisingArgumentParser()
2239 parser.add_argument('foo')
2240 group = parser.add_argument_group('g')
2241 group.add_argument('bar')
2242 parser.add_argument('baz')
2243 expected = NS(foo='1', bar='2', baz='3')
2244 result = parser.parse_args('1 2 3'.split())
2245 self.assertEqual(expected, result)
2246
2247 def test_group_first(self):
2248 parser = ErrorRaisingArgumentParser()
2249 group = parser.add_argument_group('xxx')
2250 group.add_argument('foo')
2251 parser.add_argument('bar')
2252 parser.add_argument('baz')
2253 expected = NS(foo='1', bar='2', baz='3')
2254 result = parser.parse_args('1 2 3'.split())
2255 self.assertEqual(expected, result)
2256
2257 def test_interleaved_groups(self):
2258 parser = ErrorRaisingArgumentParser()
2259 group = parser.add_argument_group('xxx')
2260 parser.add_argument('foo')
2261 group.add_argument('bar')
2262 parser.add_argument('baz')
2263 group = parser.add_argument_group('yyy')
2264 group.add_argument('frell')
2265 expected = NS(foo='1', bar='2', baz='3', frell='4')
2266 result = parser.parse_args('1 2 3 4'.split())
2267 self.assertEqual(expected, result)
2268
2269# ===================
2270# Parent parser tests
2271# ===================
2272
2273class TestParentParsers(TestCase):
2274 """Tests that parsers can be created with parent parsers"""
2275
2276 def assertArgumentParserError(self, *args, **kwargs):
2277 self.assertRaises(ArgumentParserError, *args, **kwargs)
2278
2279 def setUp(self):
Steven Bethard1f1c2472010-11-01 13:56:09 +00002280 super().setUp()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002281 self.wxyz_parent = ErrorRaisingArgumentParser(add_help=False)
2282 self.wxyz_parent.add_argument('--w')
2283 x_group = self.wxyz_parent.add_argument_group('x')
2284 x_group.add_argument('-y')
2285 self.wxyz_parent.add_argument('z')
2286
2287 self.abcd_parent = ErrorRaisingArgumentParser(add_help=False)
2288 self.abcd_parent.add_argument('a')
2289 self.abcd_parent.add_argument('-b')
2290 c_group = self.abcd_parent.add_argument_group('c')
2291 c_group.add_argument('--d')
2292
2293 self.w_parent = ErrorRaisingArgumentParser(add_help=False)
2294 self.w_parent.add_argument('--w')
2295
2296 self.z_parent = ErrorRaisingArgumentParser(add_help=False)
2297 self.z_parent.add_argument('z')
2298
2299 # parents with mutually exclusive groups
2300 self.ab_mutex_parent = ErrorRaisingArgumentParser(add_help=False)
2301 group = self.ab_mutex_parent.add_mutually_exclusive_group()
2302 group.add_argument('-a', action='store_true')
2303 group.add_argument('-b', action='store_true')
2304
2305 self.main_program = os.path.basename(sys.argv[0])
2306
2307 def test_single_parent(self):
2308 parser = ErrorRaisingArgumentParser(parents=[self.wxyz_parent])
2309 self.assertEqual(parser.parse_args('-y 1 2 --w 3'.split()),
2310 NS(w='3', y='1', z='2'))
2311
2312 def test_single_parent_mutex(self):
2313 self._test_mutex_ab(self.ab_mutex_parent.parse_args)
2314 parser = ErrorRaisingArgumentParser(parents=[self.ab_mutex_parent])
2315 self._test_mutex_ab(parser.parse_args)
2316
2317 def test_single_granparent_mutex(self):
2318 parents = [self.ab_mutex_parent]
2319 parser = ErrorRaisingArgumentParser(add_help=False, parents=parents)
2320 parser = ErrorRaisingArgumentParser(parents=[parser])
2321 self._test_mutex_ab(parser.parse_args)
2322
2323 def _test_mutex_ab(self, parse_args):
2324 self.assertEqual(parse_args([]), NS(a=False, b=False))
2325 self.assertEqual(parse_args(['-a']), NS(a=True, b=False))
2326 self.assertEqual(parse_args(['-b']), NS(a=False, b=True))
2327 self.assertArgumentParserError(parse_args, ['-a', '-b'])
2328 self.assertArgumentParserError(parse_args, ['-b', '-a'])
2329 self.assertArgumentParserError(parse_args, ['-c'])
2330 self.assertArgumentParserError(parse_args, ['-a', '-c'])
2331 self.assertArgumentParserError(parse_args, ['-b', '-c'])
2332
2333 def test_multiple_parents(self):
2334 parents = [self.abcd_parent, self.wxyz_parent]
2335 parser = ErrorRaisingArgumentParser(parents=parents)
2336 self.assertEqual(parser.parse_args('--d 1 --w 2 3 4'.split()),
2337 NS(a='3', b=None, d='1', w='2', y=None, z='4'))
2338
2339 def test_multiple_parents_mutex(self):
2340 parents = [self.ab_mutex_parent, self.wxyz_parent]
2341 parser = ErrorRaisingArgumentParser(parents=parents)
2342 self.assertEqual(parser.parse_args('-a --w 2 3'.split()),
2343 NS(a=True, b=False, w='2', y=None, z='3'))
2344 self.assertArgumentParserError(
2345 parser.parse_args, '-a --w 2 3 -b'.split())
2346 self.assertArgumentParserError(
2347 parser.parse_args, '-a -b --w 2 3'.split())
2348
2349 def test_conflicting_parents(self):
2350 self.assertRaises(
2351 argparse.ArgumentError,
2352 argparse.ArgumentParser,
2353 parents=[self.w_parent, self.wxyz_parent])
2354
2355 def test_conflicting_parents_mutex(self):
2356 self.assertRaises(
2357 argparse.ArgumentError,
2358 argparse.ArgumentParser,
2359 parents=[self.abcd_parent, self.ab_mutex_parent])
2360
2361 def test_same_argument_name_parents(self):
2362 parents = [self.wxyz_parent, self.z_parent]
2363 parser = ErrorRaisingArgumentParser(parents=parents)
2364 self.assertEqual(parser.parse_args('1 2'.split()),
2365 NS(w=None, y=None, z='2'))
2366
2367 def test_subparser_parents(self):
2368 parser = ErrorRaisingArgumentParser()
2369 subparsers = parser.add_subparsers()
2370 abcde_parser = subparsers.add_parser('bar', parents=[self.abcd_parent])
2371 abcde_parser.add_argument('e')
2372 self.assertEqual(parser.parse_args('bar -b 1 --d 2 3 4'.split()),
2373 NS(a='3', b='1', d='2', e='4'))
2374
2375 def test_subparser_parents_mutex(self):
2376 parser = ErrorRaisingArgumentParser()
2377 subparsers = parser.add_subparsers()
2378 parents = [self.ab_mutex_parent]
2379 abc_parser = subparsers.add_parser('foo', parents=parents)
2380 c_group = abc_parser.add_argument_group('c_group')
2381 c_group.add_argument('c')
2382 parents = [self.wxyz_parent, self.ab_mutex_parent]
2383 wxyzabe_parser = subparsers.add_parser('bar', parents=parents)
2384 wxyzabe_parser.add_argument('e')
2385 self.assertEqual(parser.parse_args('foo -a 4'.split()),
2386 NS(a=True, b=False, c='4'))
2387 self.assertEqual(parser.parse_args('bar -b --w 2 3 4'.split()),
2388 NS(a=False, b=True, w='2', y=None, z='3', e='4'))
2389 self.assertArgumentParserError(
2390 parser.parse_args, 'foo -a -b 4'.split())
2391 self.assertArgumentParserError(
2392 parser.parse_args, 'bar -b -a 4'.split())
2393
2394 def test_parent_help(self):
2395 parents = [self.abcd_parent, self.wxyz_parent]
2396 parser = ErrorRaisingArgumentParser(parents=parents)
2397 parser_help = parser.format_help()
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002398 progname = self.main_program
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002399 self.assertEqual(parser_help, textwrap.dedent('''\
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002400 usage: {}{}[-h] [-b B] [--d D] [--w W] [-y Y] a z
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002401
2402 positional arguments:
2403 a
2404 z
2405
2406 optional arguments:
2407 -h, --help show this help message and exit
2408 -b B
2409 --w W
2410
2411 c:
2412 --d D
2413
2414 x:
2415 -y Y
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002416 '''.format(progname, ' ' if progname else '' )))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002417
2418 def test_groups_parents(self):
2419 parent = ErrorRaisingArgumentParser(add_help=False)
2420 g = parent.add_argument_group(title='g', description='gd')
2421 g.add_argument('-w')
2422 g.add_argument('-x')
2423 m = parent.add_mutually_exclusive_group()
2424 m.add_argument('-y')
2425 m.add_argument('-z')
2426 parser = ErrorRaisingArgumentParser(parents=[parent])
2427
2428 self.assertRaises(ArgumentParserError, parser.parse_args,
2429 ['-y', 'Y', '-z', 'Z'])
2430
2431 parser_help = parser.format_help()
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002432 progname = self.main_program
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002433 self.assertEqual(parser_help, textwrap.dedent('''\
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002434 usage: {}{}[-h] [-w W] [-x X] [-y Y | -z Z]
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002435
2436 optional arguments:
2437 -h, --help show this help message and exit
2438 -y Y
2439 -z Z
2440
2441 g:
2442 gd
2443
2444 -w W
2445 -x X
Terry Jan Reedyee91e092012-01-09 18:20:09 -05002446 '''.format(progname, ' ' if progname else '' )))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002447
2448# ==============================
2449# Mutually exclusive group tests
2450# ==============================
2451
2452class TestMutuallyExclusiveGroupErrors(TestCase):
2453
2454 def test_invalid_add_argument_group(self):
2455 parser = ErrorRaisingArgumentParser()
2456 raises = self.assertRaises
2457 raises(TypeError, parser.add_mutually_exclusive_group, title='foo')
2458
2459 def test_invalid_add_argument(self):
2460 parser = ErrorRaisingArgumentParser()
2461 group = parser.add_mutually_exclusive_group()
2462 add_argument = group.add_argument
2463 raises = self.assertRaises
2464 raises(ValueError, add_argument, '--foo', required=True)
2465 raises(ValueError, add_argument, 'bar')
2466 raises(ValueError, add_argument, 'bar', nargs='+')
2467 raises(ValueError, add_argument, 'bar', nargs=1)
2468 raises(ValueError, add_argument, 'bar', nargs=argparse.PARSER)
2469
Steven Bethard49998ee2010-11-01 16:29:26 +00002470 def test_help(self):
2471 parser = ErrorRaisingArgumentParser(prog='PROG')
2472 group1 = parser.add_mutually_exclusive_group()
2473 group1.add_argument('--foo', action='store_true')
2474 group1.add_argument('--bar', action='store_false')
2475 group2 = parser.add_mutually_exclusive_group()
2476 group2.add_argument('--soup', action='store_true')
2477 group2.add_argument('--nuts', action='store_false')
2478 expected = '''\
2479 usage: PROG [-h] [--foo | --bar] [--soup | --nuts]
2480
2481 optional arguments:
2482 -h, --help show this help message and exit
2483 --foo
2484 --bar
2485 --soup
2486 --nuts
2487 '''
2488 self.assertEqual(parser.format_help(), textwrap.dedent(expected))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002489
2490class MEMixin(object):
2491
2492 def test_failures_when_not_required(self):
2493 parse_args = self.get_parser(required=False).parse_args
2494 error = ArgumentParserError
2495 for args_string in self.failures:
2496 self.assertRaises(error, parse_args, args_string.split())
2497
2498 def test_failures_when_required(self):
2499 parse_args = self.get_parser(required=True).parse_args
2500 error = ArgumentParserError
2501 for args_string in self.failures + ['']:
2502 self.assertRaises(error, parse_args, args_string.split())
2503
2504 def test_successes_when_not_required(self):
2505 parse_args = self.get_parser(required=False).parse_args
2506 successes = self.successes + self.successes_when_not_required
2507 for args_string, expected_ns in successes:
2508 actual_ns = parse_args(args_string.split())
2509 self.assertEqual(actual_ns, expected_ns)
2510
2511 def test_successes_when_required(self):
2512 parse_args = self.get_parser(required=True).parse_args
2513 for args_string, expected_ns in self.successes:
2514 actual_ns = parse_args(args_string.split())
2515 self.assertEqual(actual_ns, expected_ns)
2516
2517 def test_usage_when_not_required(self):
2518 format_usage = self.get_parser(required=False).format_usage
2519 expected_usage = self.usage_when_not_required
2520 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2521
2522 def test_usage_when_required(self):
2523 format_usage = self.get_parser(required=True).format_usage
2524 expected_usage = self.usage_when_required
2525 self.assertEqual(format_usage(), textwrap.dedent(expected_usage))
2526
2527 def test_help_when_not_required(self):
2528 format_help = self.get_parser(required=False).format_help
2529 help = self.usage_when_not_required + self.help
2530 self.assertEqual(format_help(), textwrap.dedent(help))
2531
2532 def test_help_when_required(self):
2533 format_help = self.get_parser(required=True).format_help
2534 help = self.usage_when_required + self.help
2535 self.assertEqual(format_help(), textwrap.dedent(help))
2536
2537
2538class TestMutuallyExclusiveSimple(MEMixin, TestCase):
2539
2540 def get_parser(self, required=None):
2541 parser = ErrorRaisingArgumentParser(prog='PROG')
2542 group = parser.add_mutually_exclusive_group(required=required)
2543 group.add_argument('--bar', help='bar help')
2544 group.add_argument('--baz', nargs='?', const='Z', help='baz help')
2545 return parser
2546
2547 failures = ['--bar X --baz Y', '--bar X --baz']
2548 successes = [
2549 ('--bar X', NS(bar='X', baz=None)),
2550 ('--bar X --bar Z', NS(bar='Z', baz=None)),
2551 ('--baz Y', NS(bar=None, baz='Y')),
2552 ('--baz', NS(bar=None, baz='Z')),
2553 ]
2554 successes_when_not_required = [
2555 ('', NS(bar=None, baz=None)),
2556 ]
2557
2558 usage_when_not_required = '''\
2559 usage: PROG [-h] [--bar BAR | --baz [BAZ]]
2560 '''
2561 usage_when_required = '''\
2562 usage: PROG [-h] (--bar BAR | --baz [BAZ])
2563 '''
2564 help = '''\
2565
2566 optional arguments:
2567 -h, --help show this help message and exit
2568 --bar BAR bar help
2569 --baz [BAZ] baz help
2570 '''
2571
2572
2573class TestMutuallyExclusiveLong(MEMixin, TestCase):
2574
2575 def get_parser(self, required=None):
2576 parser = ErrorRaisingArgumentParser(prog='PROG')
2577 parser.add_argument('--abcde', help='abcde help')
2578 parser.add_argument('--fghij', help='fghij help')
2579 group = parser.add_mutually_exclusive_group(required=required)
2580 group.add_argument('--klmno', help='klmno help')
2581 group.add_argument('--pqrst', help='pqrst help')
2582 return parser
2583
2584 failures = ['--klmno X --pqrst Y']
2585 successes = [
2586 ('--klmno X', NS(abcde=None, fghij=None, klmno='X', pqrst=None)),
2587 ('--abcde Y --klmno X',
2588 NS(abcde='Y', fghij=None, klmno='X', pqrst=None)),
2589 ('--pqrst X', NS(abcde=None, fghij=None, klmno=None, pqrst='X')),
2590 ('--pqrst X --fghij Y',
2591 NS(abcde=None, fghij='Y', klmno=None, pqrst='X')),
2592 ]
2593 successes_when_not_required = [
2594 ('', NS(abcde=None, fghij=None, klmno=None, pqrst=None)),
2595 ]
2596
2597 usage_when_not_required = '''\
2598 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2599 [--klmno KLMNO | --pqrst PQRST]
2600 '''
2601 usage_when_required = '''\
2602 usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ]
2603 (--klmno KLMNO | --pqrst PQRST)
2604 '''
2605 help = '''\
2606
2607 optional arguments:
2608 -h, --help show this help message and exit
2609 --abcde ABCDE abcde help
2610 --fghij FGHIJ fghij help
2611 --klmno KLMNO klmno help
2612 --pqrst PQRST pqrst help
2613 '''
2614
2615
2616class TestMutuallyExclusiveFirstSuppressed(MEMixin, TestCase):
2617
2618 def get_parser(self, required):
2619 parser = ErrorRaisingArgumentParser(prog='PROG')
2620 group = parser.add_mutually_exclusive_group(required=required)
2621 group.add_argument('-x', help=argparse.SUPPRESS)
2622 group.add_argument('-y', action='store_false', help='y help')
2623 return parser
2624
2625 failures = ['-x X -y']
2626 successes = [
2627 ('-x X', NS(x='X', y=True)),
2628 ('-x X -x Y', NS(x='Y', y=True)),
2629 ('-y', NS(x=None, y=False)),
2630 ]
2631 successes_when_not_required = [
2632 ('', NS(x=None, y=True)),
2633 ]
2634
2635 usage_when_not_required = '''\
2636 usage: PROG [-h] [-y]
2637 '''
2638 usage_when_required = '''\
2639 usage: PROG [-h] -y
2640 '''
2641 help = '''\
2642
2643 optional arguments:
2644 -h, --help show this help message and exit
2645 -y y help
2646 '''
2647
2648
2649class TestMutuallyExclusiveManySuppressed(MEMixin, TestCase):
2650
2651 def get_parser(self, required):
2652 parser = ErrorRaisingArgumentParser(prog='PROG')
2653 group = parser.add_mutually_exclusive_group(required=required)
2654 add = group.add_argument
2655 add('--spam', action='store_true', help=argparse.SUPPRESS)
2656 add('--badger', action='store_false', help=argparse.SUPPRESS)
2657 add('--bladder', help=argparse.SUPPRESS)
2658 return parser
2659
2660 failures = [
2661 '--spam --badger',
2662 '--badger --bladder B',
2663 '--bladder B --spam',
2664 ]
2665 successes = [
2666 ('--spam', NS(spam=True, badger=True, bladder=None)),
2667 ('--badger', NS(spam=False, badger=False, bladder=None)),
2668 ('--bladder B', NS(spam=False, badger=True, bladder='B')),
2669 ('--spam --spam', NS(spam=True, badger=True, bladder=None)),
2670 ]
2671 successes_when_not_required = [
2672 ('', NS(spam=False, badger=True, bladder=None)),
2673 ]
2674
2675 usage_when_required = usage_when_not_required = '''\
2676 usage: PROG [-h]
2677 '''
2678 help = '''\
2679
2680 optional arguments:
2681 -h, --help show this help message and exit
2682 '''
2683
2684
2685class TestMutuallyExclusiveOptionalAndPositional(MEMixin, TestCase):
2686
2687 def get_parser(self, required):
2688 parser = ErrorRaisingArgumentParser(prog='PROG')
2689 group = parser.add_mutually_exclusive_group(required=required)
2690 group.add_argument('--foo', action='store_true', help='FOO')
2691 group.add_argument('--spam', help='SPAM')
2692 group.add_argument('badger', nargs='*', default='X', help='BADGER')
2693 return parser
2694
2695 failures = [
2696 '--foo --spam S',
2697 '--spam S X',
2698 'X --foo',
2699 'X Y Z --spam S',
2700 '--foo X Y',
2701 ]
2702 successes = [
2703 ('--foo', NS(foo=True, spam=None, badger='X')),
2704 ('--spam S', NS(foo=False, spam='S', badger='X')),
2705 ('X', NS(foo=False, spam=None, badger=['X'])),
2706 ('X Y Z', NS(foo=False, spam=None, badger=['X', 'Y', 'Z'])),
2707 ]
2708 successes_when_not_required = [
2709 ('', NS(foo=False, spam=None, badger='X')),
2710 ]
2711
2712 usage_when_not_required = '''\
2713 usage: PROG [-h] [--foo | --spam SPAM | badger [badger ...]]
2714 '''
2715 usage_when_required = '''\
2716 usage: PROG [-h] (--foo | --spam SPAM | badger [badger ...])
2717 '''
2718 help = '''\
2719
2720 positional arguments:
2721 badger BADGER
2722
2723 optional arguments:
2724 -h, --help show this help message and exit
2725 --foo FOO
2726 --spam SPAM SPAM
2727 '''
2728
2729
2730class TestMutuallyExclusiveOptionalsMixed(MEMixin, TestCase):
2731
2732 def get_parser(self, required):
2733 parser = ErrorRaisingArgumentParser(prog='PROG')
2734 parser.add_argument('-x', action='store_true', help='x help')
2735 group = parser.add_mutually_exclusive_group(required=required)
2736 group.add_argument('-a', action='store_true', help='a help')
2737 group.add_argument('-b', action='store_true', help='b help')
2738 parser.add_argument('-y', action='store_true', help='y help')
2739 group.add_argument('-c', action='store_true', help='c help')
2740 return parser
2741
2742 failures = ['-a -b', '-b -c', '-a -c', '-a -b -c']
2743 successes = [
2744 ('-a', NS(a=True, b=False, c=False, x=False, y=False)),
2745 ('-b', NS(a=False, b=True, c=False, x=False, y=False)),
2746 ('-c', NS(a=False, b=False, c=True, x=False, y=False)),
2747 ('-a -x', NS(a=True, b=False, c=False, x=True, y=False)),
2748 ('-y -b', NS(a=False, b=True, c=False, x=False, y=True)),
2749 ('-x -y -c', NS(a=False, b=False, c=True, x=True, y=True)),
2750 ]
2751 successes_when_not_required = [
2752 ('', NS(a=False, b=False, c=False, x=False, y=False)),
2753 ('-x', NS(a=False, b=False, c=False, x=True, y=False)),
2754 ('-y', NS(a=False, b=False, c=False, x=False, y=True)),
2755 ]
2756
2757 usage_when_required = usage_when_not_required = '''\
2758 usage: PROG [-h] [-x] [-a] [-b] [-y] [-c]
2759 '''
2760 help = '''\
2761
2762 optional arguments:
2763 -h, --help show this help message and exit
2764 -x x help
2765 -a a help
2766 -b b help
2767 -y y help
2768 -c c help
2769 '''
2770
2771
Georg Brandl0f6b47a2011-01-30 12:19:35 +00002772class TestMutuallyExclusiveInGroup(MEMixin, TestCase):
2773
2774 def get_parser(self, required=None):
2775 parser = ErrorRaisingArgumentParser(prog='PROG')
2776 titled_group = parser.add_argument_group(
2777 title='Titled group', description='Group description')
2778 mutex_group = \
2779 titled_group.add_mutually_exclusive_group(required=required)
2780 mutex_group.add_argument('--bar', help='bar help')
2781 mutex_group.add_argument('--baz', help='baz help')
2782 return parser
2783
2784 failures = ['--bar X --baz Y', '--baz X --bar Y']
2785 successes = [
2786 ('--bar X', NS(bar='X', baz=None)),
2787 ('--baz Y', NS(bar=None, baz='Y')),
2788 ]
2789 successes_when_not_required = [
2790 ('', NS(bar=None, baz=None)),
2791 ]
2792
2793 usage_when_not_required = '''\
2794 usage: PROG [-h] [--bar BAR | --baz BAZ]
2795 '''
2796 usage_when_required = '''\
2797 usage: PROG [-h] (--bar BAR | --baz BAZ)
2798 '''
2799 help = '''\
2800
2801 optional arguments:
2802 -h, --help show this help message and exit
2803
2804 Titled group:
2805 Group description
2806
2807 --bar BAR bar help
2808 --baz BAZ baz help
2809 '''
2810
2811
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002812class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase):
2813
2814 def get_parser(self, required):
2815 parser = ErrorRaisingArgumentParser(prog='PROG')
2816 parser.add_argument('x', help='x help')
2817 parser.add_argument('-y', action='store_true', help='y help')
2818 group = parser.add_mutually_exclusive_group(required=required)
2819 group.add_argument('a', nargs='?', help='a help')
2820 group.add_argument('-b', action='store_true', help='b help')
2821 group.add_argument('-c', action='store_true', help='c help')
2822 return parser
2823
2824 failures = ['X A -b', '-b -c', '-c X A']
2825 successes = [
2826 ('X A', NS(a='A', b=False, c=False, x='X', y=False)),
2827 ('X -b', NS(a=None, b=True, c=False, x='X', y=False)),
2828 ('X -c', NS(a=None, b=False, c=True, x='X', y=False)),
2829 ('X A -y', NS(a='A', b=False, c=False, x='X', y=True)),
2830 ('X -y -b', NS(a=None, b=True, c=False, x='X', y=True)),
2831 ]
2832 successes_when_not_required = [
2833 ('X', NS(a=None, b=False, c=False, x='X', y=False)),
2834 ('X -y', NS(a=None, b=False, c=False, x='X', y=True)),
2835 ]
2836
2837 usage_when_required = usage_when_not_required = '''\
2838 usage: PROG [-h] [-y] [-b] [-c] x [a]
2839 '''
2840 help = '''\
2841
2842 positional arguments:
2843 x x help
2844 a a help
2845
2846 optional arguments:
2847 -h, --help show this help message and exit
2848 -y y help
2849 -b b help
2850 -c c help
2851 '''
2852
Raymond Hettingerbd8ca9a2019-08-30 15:25:38 -07002853class TestMutuallyExclusiveNested(MEMixin, TestCase):
2854
2855 def get_parser(self, required):
2856 parser = ErrorRaisingArgumentParser(prog='PROG')
2857 group = parser.add_mutually_exclusive_group(required=required)
2858 group.add_argument('-a')
2859 group.add_argument('-b')
2860 group2 = group.add_mutually_exclusive_group(required=required)
2861 group2.add_argument('-c')
2862 group2.add_argument('-d')
2863 group3 = group2.add_mutually_exclusive_group(required=required)
2864 group3.add_argument('-e')
2865 group3.add_argument('-f')
2866 return parser
2867
2868 usage_when_not_required = '''\
2869 usage: PROG [-h] [-a A | -b B | [-c C | -d D | [-e E | -f F]]]
2870 '''
2871 usage_when_required = '''\
2872 usage: PROG [-h] (-a A | -b B | (-c C | -d D | (-e E | -f F)))
2873 '''
2874
2875 help = '''\
2876
2877 optional arguments:
2878 -h, --help show this help message and exit
2879 -a A
2880 -b B
2881 -c C
2882 -d D
2883 -e E
2884 -f F
2885 '''
2886
2887 # We are only interested in testing the behavior of format_usage().
2888 test_failures_when_not_required = None
2889 test_failures_when_required = None
2890 test_successes_when_not_required = None
2891 test_successes_when_required = None
2892
Benjamin Peterson698a18a2010-03-02 22:34:37 +00002893# =================================================
2894# Mutually exclusive group in parent parser tests
2895# =================================================
2896
2897class MEPBase(object):
2898
2899 def get_parser(self, required=None):
2900 parent = super(MEPBase, self).get_parser(required=required)
2901 parser = ErrorRaisingArgumentParser(
2902 prog=parent.prog, add_help=False, parents=[parent])
2903 return parser
2904
2905
2906class TestMutuallyExclusiveGroupErrorsParent(
2907 MEPBase, TestMutuallyExclusiveGroupErrors):
2908 pass
2909
2910
2911class TestMutuallyExclusiveSimpleParent(
2912 MEPBase, TestMutuallyExclusiveSimple):
2913 pass
2914
2915
2916class TestMutuallyExclusiveLongParent(
2917 MEPBase, TestMutuallyExclusiveLong):
2918 pass
2919
2920
2921class TestMutuallyExclusiveFirstSuppressedParent(
2922 MEPBase, TestMutuallyExclusiveFirstSuppressed):
2923 pass
2924
2925
2926class TestMutuallyExclusiveManySuppressedParent(
2927 MEPBase, TestMutuallyExclusiveManySuppressed):
2928 pass
2929
2930
2931class TestMutuallyExclusiveOptionalAndPositionalParent(
2932 MEPBase, TestMutuallyExclusiveOptionalAndPositional):
2933 pass
2934
2935
2936class TestMutuallyExclusiveOptionalsMixedParent(
2937 MEPBase, TestMutuallyExclusiveOptionalsMixed):
2938 pass
2939
2940
2941class TestMutuallyExclusiveOptionalsAndPositionalsMixedParent(
2942 MEPBase, TestMutuallyExclusiveOptionalsAndPositionalsMixed):
2943 pass
2944
2945# =================
2946# Set default tests
2947# =================
2948
2949class TestSetDefaults(TestCase):
2950
2951 def test_set_defaults_no_args(self):
2952 parser = ErrorRaisingArgumentParser()
2953 parser.set_defaults(x='foo')
2954 parser.set_defaults(y='bar', z=1)
2955 self.assertEqual(NS(x='foo', y='bar', z=1),
2956 parser.parse_args([]))
2957 self.assertEqual(NS(x='foo', y='bar', z=1),
2958 parser.parse_args([], NS()))
2959 self.assertEqual(NS(x='baz', y='bar', z=1),
2960 parser.parse_args([], NS(x='baz')))
2961 self.assertEqual(NS(x='baz', y='bar', z=2),
2962 parser.parse_args([], NS(x='baz', z=2)))
2963
2964 def test_set_defaults_with_args(self):
2965 parser = ErrorRaisingArgumentParser()
2966 parser.set_defaults(x='foo', y='bar')
2967 parser.add_argument('-x', default='xfoox')
2968 self.assertEqual(NS(x='xfoox', y='bar'),
2969 parser.parse_args([]))
2970 self.assertEqual(NS(x='xfoox', y='bar'),
2971 parser.parse_args([], NS()))
2972 self.assertEqual(NS(x='baz', y='bar'),
2973 parser.parse_args([], NS(x='baz')))
2974 self.assertEqual(NS(x='1', y='bar'),
2975 parser.parse_args('-x 1'.split()))
2976 self.assertEqual(NS(x='1', y='bar'),
2977 parser.parse_args('-x 1'.split(), NS()))
2978 self.assertEqual(NS(x='1', y='bar'),
2979 parser.parse_args('-x 1'.split(), NS(x='baz')))
2980
2981 def test_set_defaults_subparsers(self):
2982 parser = ErrorRaisingArgumentParser()
2983 parser.set_defaults(x='foo')
2984 subparsers = parser.add_subparsers()
2985 parser_a = subparsers.add_parser('a')
2986 parser_a.set_defaults(y='bar')
2987 self.assertEqual(NS(x='foo', y='bar'),
2988 parser.parse_args('a'.split()))
2989
2990 def test_set_defaults_parents(self):
2991 parent = ErrorRaisingArgumentParser(add_help=False)
2992 parent.set_defaults(x='foo')
2993 parser = ErrorRaisingArgumentParser(parents=[parent])
2994 self.assertEqual(NS(x='foo'), parser.parse_args([]))
2995
R David Murray7570cbd2014-10-17 19:55:11 -04002996 def test_set_defaults_on_parent_and_subparser(self):
2997 parser = argparse.ArgumentParser()
2998 xparser = parser.add_subparsers().add_parser('X')
2999 parser.set_defaults(foo=1)
3000 xparser.set_defaults(foo=2)
3001 self.assertEqual(NS(foo=2), parser.parse_args(['X']))
3002
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003003 def test_set_defaults_same_as_add_argument(self):
3004 parser = ErrorRaisingArgumentParser()
3005 parser.set_defaults(w='W', x='X', y='Y', z='Z')
3006 parser.add_argument('-w')
3007 parser.add_argument('-x', default='XX')
3008 parser.add_argument('y', nargs='?')
3009 parser.add_argument('z', nargs='?', default='ZZ')
3010
3011 # defaults set previously
3012 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
3013 parser.parse_args([]))
3014
3015 # reset defaults
3016 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
3017 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
3018 parser.parse_args([]))
3019
3020 def test_set_defaults_same_as_add_argument_group(self):
3021 parser = ErrorRaisingArgumentParser()
3022 parser.set_defaults(w='W', x='X', y='Y', z='Z')
3023 group = parser.add_argument_group('foo')
3024 group.add_argument('-w')
3025 group.add_argument('-x', default='XX')
3026 group.add_argument('y', nargs='?')
3027 group.add_argument('z', nargs='?', default='ZZ')
3028
3029
3030 # defaults set previously
3031 self.assertEqual(NS(w='W', x='XX', y='Y', z='ZZ'),
3032 parser.parse_args([]))
3033
3034 # reset defaults
3035 parser.set_defaults(w='WW', x='X', y='YY', z='Z')
3036 self.assertEqual(NS(w='WW', x='X', y='YY', z='Z'),
3037 parser.parse_args([]))
3038
3039# =================
3040# Get default tests
3041# =================
3042
3043class TestGetDefault(TestCase):
3044
3045 def test_get_default(self):
3046 parser = ErrorRaisingArgumentParser()
Berker Peksag1c5f56a2014-07-06 09:33:20 +03003047 self.assertIsNone(parser.get_default("foo"))
3048 self.assertIsNone(parser.get_default("bar"))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003049
3050 parser.add_argument("--foo")
Berker Peksag1c5f56a2014-07-06 09:33:20 +03003051 self.assertIsNone(parser.get_default("foo"))
3052 self.assertIsNone(parser.get_default("bar"))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003053
3054 parser.add_argument("--bar", type=int, default=42)
Berker Peksag1c5f56a2014-07-06 09:33:20 +03003055 self.assertIsNone(parser.get_default("foo"))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003056 self.assertEqual(42, parser.get_default("bar"))
3057
3058 parser.set_defaults(foo="badger")
3059 self.assertEqual("badger", parser.get_default("foo"))
3060 self.assertEqual(42, parser.get_default("bar"))
3061
3062# ==========================
3063# Namespace 'contains' tests
3064# ==========================
3065
3066class TestNamespaceContainsSimple(TestCase):
3067
3068 def test_empty(self):
3069 ns = argparse.Namespace()
Berker Peksag1c5f56a2014-07-06 09:33:20 +03003070 self.assertNotIn('', ns)
3071 self.assertNotIn('x', ns)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003072
3073 def test_non_empty(self):
3074 ns = argparse.Namespace(x=1, y=2)
Berker Peksag1c5f56a2014-07-06 09:33:20 +03003075 self.assertNotIn('', ns)
3076 self.assertIn('x', ns)
3077 self.assertIn('y', ns)
3078 self.assertNotIn('xx', ns)
3079 self.assertNotIn('z', ns)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003080
3081# =====================
3082# Help formatting tests
3083# =====================
3084
3085class TestHelpFormattingMetaclass(type):
3086
3087 def __init__(cls, name, bases, bodydict):
3088 if name == 'HelpTestCase':
3089 return
3090
3091 class AddTests(object):
3092
3093 def __init__(self, test_class, func_suffix, std_name):
3094 self.func_suffix = func_suffix
3095 self.std_name = std_name
3096
3097 for test_func in [self.test_format,
3098 self.test_print,
3099 self.test_print_file]:
3100 test_name = '%s_%s' % (test_func.__name__, func_suffix)
3101
3102 def test_wrapper(self, test_func=test_func):
3103 test_func(self)
3104 try:
3105 test_wrapper.__name__ = test_name
3106 except TypeError:
3107 pass
3108 setattr(test_class, test_name, test_wrapper)
3109
3110 def _get_parser(self, tester):
3111 parser = argparse.ArgumentParser(
3112 *tester.parser_signature.args,
3113 **tester.parser_signature.kwargs)
Steven Bethard8a6a1982011-03-27 13:53:53 +02003114 for argument_sig in getattr(tester, 'argument_signatures', []):
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003115 parser.add_argument(*argument_sig.args,
3116 **argument_sig.kwargs)
Steven Bethard8a6a1982011-03-27 13:53:53 +02003117 group_sigs = getattr(tester, 'argument_group_signatures', [])
3118 for group_sig, argument_sigs in group_sigs:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003119 group = parser.add_argument_group(*group_sig.args,
3120 **group_sig.kwargs)
3121 for argument_sig in argument_sigs:
3122 group.add_argument(*argument_sig.args,
3123 **argument_sig.kwargs)
Steven Bethard8a6a1982011-03-27 13:53:53 +02003124 subparsers_sigs = getattr(tester, 'subparsers_signatures', [])
3125 if subparsers_sigs:
3126 subparsers = parser.add_subparsers()
3127 for subparser_sig in subparsers_sigs:
3128 subparsers.add_parser(*subparser_sig.args,
3129 **subparser_sig.kwargs)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003130 return parser
3131
3132 def _test(self, tester, parser_text):
3133 expected_text = getattr(tester, self.func_suffix)
3134 expected_text = textwrap.dedent(expected_text)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003135 tester.assertEqual(expected_text, parser_text)
3136
3137 def test_format(self, tester):
3138 parser = self._get_parser(tester)
3139 format = getattr(parser, 'format_%s' % self.func_suffix)
3140 self._test(tester, format())
3141
3142 def test_print(self, tester):
3143 parser = self._get_parser(tester)
3144 print_ = getattr(parser, 'print_%s' % self.func_suffix)
3145 old_stream = getattr(sys, self.std_name)
Benjamin Petersonb48af542010-04-11 20:43:16 +00003146 setattr(sys, self.std_name, StdIOBuffer())
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003147 try:
3148 print_()
3149 parser_text = getattr(sys, self.std_name).getvalue()
3150 finally:
3151 setattr(sys, self.std_name, old_stream)
3152 self._test(tester, parser_text)
3153
3154 def test_print_file(self, tester):
3155 parser = self._get_parser(tester)
3156 print_ = getattr(parser, 'print_%s' % self.func_suffix)
Benjamin Petersonb48af542010-04-11 20:43:16 +00003157 sfile = StdIOBuffer()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003158 print_(sfile)
3159 parser_text = sfile.getvalue()
3160 self._test(tester, parser_text)
3161
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003162 # add tests for {format,print}_{usage,help}
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003163 for func_suffix, std_name in [('usage', 'stdout'),
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003164 ('help', 'stdout')]:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003165 AddTests(cls, func_suffix, std_name)
3166
3167bases = TestCase,
3168HelpTestCase = TestHelpFormattingMetaclass('HelpTestCase', bases, {})
3169
3170
3171class TestHelpBiggerOptionals(HelpTestCase):
3172 """Make sure that argument help aligns when options are longer"""
3173
3174 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003175 epilog='EPILOG')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003176 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003177 Sig('-v', '--version', action='version', version='0.1'),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003178 Sig('-x', action='store_true', help='X HELP'),
3179 Sig('--y', help='Y HELP'),
3180 Sig('foo', help='FOO HELP'),
3181 Sig('bar', help='BAR HELP'),
3182 ]
3183 argument_group_signatures = []
3184 usage = '''\
3185 usage: PROG [-h] [-v] [-x] [--y Y] foo bar
3186 '''
3187 help = usage + '''\
3188
3189 DESCRIPTION
3190
3191 positional arguments:
3192 foo FOO HELP
3193 bar BAR HELP
3194
3195 optional arguments:
3196 -h, --help show this help message and exit
3197 -v, --version show program's version number and exit
3198 -x X HELP
3199 --y Y Y HELP
3200
3201 EPILOG
3202 '''
3203 version = '''\
3204 0.1
3205 '''
3206
Serhiy Storchakaf4511122014-01-09 23:14:27 +02003207class TestShortColumns(HelpTestCase):
3208 '''Test extremely small number of columns.
3209
3210 TestCase prevents "COLUMNS" from being too small in the tests themselves,
Martin Panter2e4571a2015-11-14 01:07:43 +00003211 but we don't want any exceptions thrown in such cases. Only ugly representation.
Serhiy Storchakaf4511122014-01-09 23:14:27 +02003212 '''
3213 def setUp(self):
3214 env = support.EnvironmentVarGuard()
3215 env.set("COLUMNS", '15')
3216 self.addCleanup(env.__exit__)
3217
3218 parser_signature = TestHelpBiggerOptionals.parser_signature
3219 argument_signatures = TestHelpBiggerOptionals.argument_signatures
3220 argument_group_signatures = TestHelpBiggerOptionals.argument_group_signatures
3221 usage = '''\
3222 usage: PROG
3223 [-h]
3224 [-v]
3225 [-x]
3226 [--y Y]
3227 foo
3228 bar
3229 '''
3230 help = usage + '''\
3231
3232 DESCRIPTION
3233
3234 positional arguments:
3235 foo
3236 FOO HELP
3237 bar
3238 BAR HELP
3239
3240 optional arguments:
3241 -h, --help
3242 show this
3243 help
3244 message and
3245 exit
3246 -v, --version
3247 show
3248 program's
3249 version
3250 number and
3251 exit
3252 -x
3253 X HELP
3254 --y Y
3255 Y HELP
3256
3257 EPILOG
3258 '''
3259 version = TestHelpBiggerOptionals.version
3260
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003261
3262class TestHelpBiggerOptionalGroups(HelpTestCase):
3263 """Make sure that argument help aligns when options are longer"""
3264
3265 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003266 epilog='EPILOG')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003267 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003268 Sig('-v', '--version', action='version', version='0.1'),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003269 Sig('-x', action='store_true', help='X HELP'),
3270 Sig('--y', help='Y HELP'),
3271 Sig('foo', help='FOO HELP'),
3272 Sig('bar', help='BAR HELP'),
3273 ]
3274 argument_group_signatures = [
3275 (Sig('GROUP TITLE', description='GROUP DESCRIPTION'), [
3276 Sig('baz', help='BAZ HELP'),
3277 Sig('-z', nargs='+', help='Z HELP')]),
3278 ]
3279 usage = '''\
3280 usage: PROG [-h] [-v] [-x] [--y Y] [-z Z [Z ...]] foo bar baz
3281 '''
3282 help = usage + '''\
3283
3284 DESCRIPTION
3285
3286 positional arguments:
3287 foo FOO HELP
3288 bar BAR HELP
3289
3290 optional arguments:
3291 -h, --help show this help message and exit
3292 -v, --version show program's version number and exit
3293 -x X HELP
3294 --y Y Y HELP
3295
3296 GROUP TITLE:
3297 GROUP DESCRIPTION
3298
3299 baz BAZ HELP
3300 -z Z [Z ...] Z HELP
3301
3302 EPILOG
3303 '''
3304 version = '''\
3305 0.1
3306 '''
3307
3308
3309class TestHelpBiggerPositionals(HelpTestCase):
3310 """Make sure that help aligns when arguments are longer"""
3311
3312 parser_signature = Sig(usage='USAGE', description='DESCRIPTION')
3313 argument_signatures = [
3314 Sig('-x', action='store_true', help='X HELP'),
3315 Sig('--y', help='Y HELP'),
3316 Sig('ekiekiekifekang', help='EKI HELP'),
3317 Sig('bar', help='BAR HELP'),
3318 ]
3319 argument_group_signatures = []
3320 usage = '''\
3321 usage: USAGE
3322 '''
3323 help = usage + '''\
3324
3325 DESCRIPTION
3326
3327 positional arguments:
3328 ekiekiekifekang EKI HELP
3329 bar BAR HELP
3330
3331 optional arguments:
3332 -h, --help show this help message and exit
3333 -x X HELP
3334 --y Y Y HELP
3335 '''
3336
3337 version = ''
3338
3339
3340class TestHelpReformatting(HelpTestCase):
3341 """Make sure that text after short names starts on the first line"""
3342
3343 parser_signature = Sig(
3344 prog='PROG',
3345 description=' oddly formatted\n'
3346 'description\n'
3347 '\n'
3348 'that is so long that it should go onto multiple '
3349 'lines when wrapped')
3350 argument_signatures = [
3351 Sig('-x', metavar='XX', help='oddly\n'
3352 ' formatted -x help'),
3353 Sig('y', metavar='yyy', help='normal y help'),
3354 ]
3355 argument_group_signatures = [
3356 (Sig('title', description='\n'
3357 ' oddly formatted group\n'
3358 '\n'
3359 'description'),
3360 [Sig('-a', action='store_true',
3361 help=' oddly \n'
3362 'formatted -a help \n'
3363 ' again, so long that it should be wrapped over '
3364 'multiple lines')]),
3365 ]
3366 usage = '''\
3367 usage: PROG [-h] [-x XX] [-a] yyy
3368 '''
3369 help = usage + '''\
3370
3371 oddly formatted description that is so long that it should go onto \
3372multiple
3373 lines when wrapped
3374
3375 positional arguments:
3376 yyy normal y help
3377
3378 optional arguments:
3379 -h, --help show this help message and exit
3380 -x XX oddly formatted -x help
3381
3382 title:
3383 oddly formatted group description
3384
3385 -a oddly formatted -a help again, so long that it should \
3386be wrapped
3387 over multiple lines
3388 '''
3389 version = ''
3390
3391
3392class TestHelpWrappingShortNames(HelpTestCase):
3393 """Make sure that text after short names starts on the first line"""
3394
3395 parser_signature = Sig(prog='PROG', description= 'D\nD' * 30)
3396 argument_signatures = [
3397 Sig('-x', metavar='XX', help='XHH HX' * 20),
3398 Sig('y', metavar='yyy', help='YH YH' * 20),
3399 ]
3400 argument_group_signatures = [
3401 (Sig('ALPHAS'), [
3402 Sig('-a', action='store_true', help='AHHH HHA' * 10)]),
3403 ]
3404 usage = '''\
3405 usage: PROG [-h] [-x XX] [-a] yyy
3406 '''
3407 help = usage + '''\
3408
3409 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3410DD DD DD
3411 DD DD DD DD D
3412
3413 positional arguments:
3414 yyy YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3415YHYH YHYH
3416 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3417
3418 optional arguments:
3419 -h, --help show this help message and exit
3420 -x XX XHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH \
3421HXXHH HXXHH
3422 HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HX
3423
3424 ALPHAS:
3425 -a AHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH \
3426HHAAHHH
3427 HHAAHHH HHAAHHH HHA
3428 '''
3429 version = ''
3430
3431
3432class TestHelpWrappingLongNames(HelpTestCase):
3433 """Make sure that text after long names starts on the next line"""
3434
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003435 parser_signature = Sig(usage='USAGE', description= 'D D' * 30)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003436 argument_signatures = [
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02003437 Sig('-v', '--version', action='version', version='V V' * 30),
Benjamin Peterson698a18a2010-03-02 22:34:37 +00003438 Sig('-x', metavar='X' * 25, help='XH XH' * 20),
3439 Sig('y', metavar='y' * 25, help='YH YH' * 20),
3440 ]
3441 argument_group_signatures = [
3442 (Sig('ALPHAS'), [
3443 Sig('-a', metavar='A' * 25, help='AH AH' * 20),
3444 Sig('z', metavar='z' * 25, help='ZH ZH' * 20)]),
3445 ]
3446 usage = '''\
3447 usage: USAGE
3448 '''
3449 help = usage + '''\
3450
3451 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3452DD DD DD
3453 DD DD DD DD D
3454
3455 positional arguments:
3456 yyyyyyyyyyyyyyyyyyyyyyyyy
3457 YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3458YHYH YHYH
3459 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3460
3461 optional arguments:
3462 -h, --help show this help message and exit
3463 -v, --version show program's version number and exit
3464 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3465 XH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH \
3466XHXH XHXH
3467 XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XH
3468
3469 ALPHAS:
3470 -a AAAAAAAAAAAAAAAAAAAAAAAAA
3471 AH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH \
3472AHAH AHAH
3473 AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AH
3474 zzzzzzzzzzzzzzzzzzzzzzzzz
3475 ZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH \
3476ZHZH ZHZH
3477 ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZH
3478 '''
3479 version = '''\
3480 V VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV \
3481VV VV VV
3482 VV VV VV VV V
3483 '''
3484
3485
3486class TestHelpUsage(HelpTestCase):
3487 """Test basic usage messages"""
3488
3489 parser_signature = Sig(prog='PROG')
3490 argument_signatures = [
3491 Sig('-w', nargs='+', help='w'),
3492 Sig('-x', nargs='*', help='x'),
3493 Sig('a', help='a'),
3494 Sig('b', help='b', nargs=2),
3495 Sig('c', help='c', nargs='?'),
3496 ]
3497 argument_group_signatures = [
3498 (Sig('group'), [
3499 Sig('-y', nargs='?', help='y'),
3500 Sig('-z', nargs=3, help='z'),
3501 Sig('d', help='d', nargs='*'),
3502 Sig('e', help='e', nargs='+'),
3503 ])
3504 ]
3505 usage = '''\
3506 usage: PROG [-h] [-w W [W ...]] [-x [X [X ...]]] [-y [Y]] [-z Z Z Z]
3507 a b b [c] [d [d ...]] e [e ...]
3508 '''
3509 help = usage + '''\
3510
3511 positional arguments:
3512 a a
3513 b b
3514 c c
3515
3516 optional arguments:
3517 -h, --help show this help message and exit
3518 -w W [W ...] w
3519 -x [X [X ...]] x
3520
3521 group:
3522 -y [Y] y
3523 -z Z Z Z z
3524 d d
3525 e e
3526 '''
3527 version = ''
3528
3529
3530class TestHelpOnlyUserGroups(HelpTestCase):
3531 """Test basic usage messages"""
3532
3533 parser_signature = Sig(prog='PROG', add_help=False)
3534 argument_signatures = []
3535 argument_group_signatures = [
3536 (Sig('xxxx'), [
3537 Sig('-x', help='x'),
3538 Sig('a', help='a'),
3539 ]),
3540 (Sig('yyyy'), [
3541 Sig('b', help='b'),
3542 Sig('-y', help='y'),
3543 ]),
3544 ]
3545 usage = '''\
3546 usage: PROG [-x X] [-y Y] a b
3547 '''
3548 help = usage + '''\
3549
3550 xxxx:
3551 -x X x
3552 a a
3553
3554 yyyy:
3555 b b
3556 -y Y y
3557 '''
3558 version = ''
3559
3560
3561class TestHelpUsageLongProg(HelpTestCase):
3562 """Test usage messages where the prog is long"""
3563
3564 parser_signature = Sig(prog='P' * 60)
3565 argument_signatures = [
3566 Sig('-w', metavar='W'),
3567 Sig('-x', metavar='X'),
3568 Sig('a'),
3569 Sig('b'),
3570 ]
3571 argument_group_signatures = []
3572 usage = '''\
3573 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3574 [-h] [-w W] [-x X] a b
3575 '''
3576 help = usage + '''\
3577
3578 positional arguments:
3579 a
3580 b
3581
3582 optional arguments:
3583 -h, --help show this help message and exit
3584 -w W
3585 -x X
3586 '''
3587 version = ''
3588
3589
3590class TestHelpUsageLongProgOptionsWrap(HelpTestCase):
3591 """Test usage messages where the prog is long and the optionals wrap"""
3592
3593 parser_signature = Sig(prog='P' * 60)
3594 argument_signatures = [
3595 Sig('-w', metavar='W' * 25),
3596 Sig('-x', metavar='X' * 25),
3597 Sig('-y', metavar='Y' * 25),
3598 Sig('-z', metavar='Z' * 25),
3599 Sig('a'),
3600 Sig('b'),
3601 ]
3602 argument_group_signatures = []
3603 usage = '''\
3604 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3605 [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3606[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3607 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3608 a b
3609 '''
3610 help = usage + '''\
3611
3612 positional arguments:
3613 a
3614 b
3615
3616 optional arguments:
3617 -h, --help show this help message and exit
3618 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3619 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3620 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3621 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3622 '''
3623 version = ''
3624
3625
3626class TestHelpUsageLongProgPositionalsWrap(HelpTestCase):
3627 """Test usage messages where the prog is long and the positionals wrap"""
3628
3629 parser_signature = Sig(prog='P' * 60, add_help=False)
3630 argument_signatures = [
3631 Sig('a' * 25),
3632 Sig('b' * 25),
3633 Sig('c' * 25),
3634 ]
3635 argument_group_signatures = []
3636 usage = '''\
3637 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3638 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3639 ccccccccccccccccccccccccc
3640 '''
3641 help = usage + '''\
3642
3643 positional arguments:
3644 aaaaaaaaaaaaaaaaaaaaaaaaa
3645 bbbbbbbbbbbbbbbbbbbbbbbbb
3646 ccccccccccccccccccccccccc
3647 '''
3648 version = ''
3649
3650
3651class TestHelpUsageOptionalsWrap(HelpTestCase):
3652 """Test usage messages where the optionals wrap"""
3653
3654 parser_signature = Sig(prog='PROG')
3655 argument_signatures = [
3656 Sig('-w', metavar='W' * 25),
3657 Sig('-x', metavar='X' * 25),
3658 Sig('-y', metavar='Y' * 25),
3659 Sig('-z', metavar='Z' * 25),
3660 Sig('a'),
3661 Sig('b'),
3662 Sig('c'),
3663 ]
3664 argument_group_signatures = []
3665 usage = '''\
3666 usage: PROG [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3667[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3668 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] \
3669[-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3670 a b c
3671 '''
3672 help = usage + '''\
3673
3674 positional arguments:
3675 a
3676 b
3677 c
3678
3679 optional arguments:
3680 -h, --help show this help message and exit
3681 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3682 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3683 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3684 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3685 '''
3686 version = ''
3687
3688
3689class TestHelpUsagePositionalsWrap(HelpTestCase):
3690 """Test usage messages where the positionals wrap"""
3691
3692 parser_signature = Sig(prog='PROG')
3693 argument_signatures = [
3694 Sig('-x'),
3695 Sig('-y'),
3696 Sig('-z'),
3697 Sig('a' * 25),
3698 Sig('b' * 25),
3699 Sig('c' * 25),
3700 ]
3701 argument_group_signatures = []
3702 usage = '''\
3703 usage: PROG [-h] [-x X] [-y Y] [-z Z]
3704 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3705 ccccccccccccccccccccccccc
3706 '''
3707 help = usage + '''\
3708
3709 positional arguments:
3710 aaaaaaaaaaaaaaaaaaaaaaaaa
3711 bbbbbbbbbbbbbbbbbbbbbbbbb
3712 ccccccccccccccccccccccccc
3713
3714 optional arguments:
3715 -h, --help show this help message and exit
3716 -x X
3717 -y Y
3718 -z Z
3719 '''
3720 version = ''
3721
3722
3723class TestHelpUsageOptionalsPositionalsWrap(HelpTestCase):
3724 """Test usage messages where the optionals and positionals wrap"""
3725
3726 parser_signature = Sig(prog='PROG')
3727 argument_signatures = [
3728 Sig('-x', metavar='X' * 25),
3729 Sig('-y', metavar='Y' * 25),
3730 Sig('-z', metavar='Z' * 25),
3731 Sig('a' * 25),
3732 Sig('b' * 25),
3733 Sig('c' * 25),
3734 ]
3735 argument_group_signatures = []
3736 usage = '''\
3737 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3738[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3739 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3740 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3741 ccccccccccccccccccccccccc
3742 '''
3743 help = usage + '''\
3744
3745 positional arguments:
3746 aaaaaaaaaaaaaaaaaaaaaaaaa
3747 bbbbbbbbbbbbbbbbbbbbbbbbb
3748 ccccccccccccccccccccccccc
3749
3750 optional arguments:
3751 -h, --help show this help message and exit
3752 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3753 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3754 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3755 '''
3756 version = ''
3757
3758
3759class TestHelpUsageOptionalsOnlyWrap(HelpTestCase):
3760 """Test usage messages where there are only optionals and they wrap"""
3761
3762 parser_signature = Sig(prog='PROG')
3763 argument_signatures = [
3764 Sig('-x', metavar='X' * 25),
3765 Sig('-y', metavar='Y' * 25),
3766 Sig('-z', metavar='Z' * 25),
3767 ]
3768 argument_group_signatures = []
3769 usage = '''\
3770 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3771[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3772 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3773 '''
3774 help = usage + '''\
3775
3776 optional arguments:
3777 -h, --help show this help message and exit
3778 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3779 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3780 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3781 '''
3782 version = ''
3783
3784
3785class TestHelpUsagePositionalsOnlyWrap(HelpTestCase):
3786 """Test usage messages where there are only positionals and they wrap"""
3787
3788 parser_signature = Sig(prog='PROG', add_help=False)
3789 argument_signatures = [
3790 Sig('a' * 25),
3791 Sig('b' * 25),
3792 Sig('c' * 25),
3793 ]
3794 argument_group_signatures = []
3795 usage = '''\
3796 usage: PROG aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3797 ccccccccccccccccccccccccc
3798 '''
3799 help = usage + '''\
3800
3801 positional arguments:
3802 aaaaaaaaaaaaaaaaaaaaaaaaa
3803 bbbbbbbbbbbbbbbbbbbbbbbbb
3804 ccccccccccccccccccccccccc
3805 '''
3806 version = ''
3807
3808
3809class TestHelpVariableExpansion(HelpTestCase):
3810 """Test that variables are expanded properly in help messages"""
3811
3812 parser_signature = Sig(prog='PROG')
3813 argument_signatures = [
3814 Sig('-x', type=int,
3815 help='x %(prog)s %(default)s %(type)s %%'),
3816 Sig('-y', action='store_const', default=42, const='XXX',
3817 help='y %(prog)s %(default)s %(const)s'),
3818 Sig('--foo', choices='abc',
3819 help='foo %(prog)s %(default)s %(choices)s'),
3820 Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
3821 help='bar %(prog)s %(default)s %(dest)s'),
3822 Sig('spam', help='spam %(prog)s %(default)s'),
3823 Sig('badger', default=0.5, help='badger %(prog)s %(default)s'),
3824 ]
3825 argument_group_signatures = [
3826 (Sig('group'), [
3827 Sig('-a', help='a %(prog)s %(default)s'),
3828 Sig('-b', default=-1, help='b %(prog)s %(default)s'),
3829 ])
3830 ]
3831 usage = ('''\
3832 usage: PROG [-h] [-x X] [-y] [--foo {a,b,c}] [--bar BBB] [-a A] [-b B]
3833 spam badger
3834 ''')
3835 help = usage + '''\
3836
3837 positional arguments:
3838 spam spam PROG None
3839 badger badger PROG 0.5
3840
3841 optional arguments:
3842 -h, --help show this help message and exit
3843 -x X x PROG None int %
3844 -y y PROG 42 XXX
3845 --foo {a,b,c} foo PROG None a, b, c
3846 --bar BBB bar PROG baz bar
3847
3848 group:
3849 -a A a PROG None
3850 -b B b PROG -1
3851 '''
3852 version = ''
3853
3854
3855class TestHelpVariableExpansionUsageSupplied(HelpTestCase):
3856 """Test that variables are expanded properly when usage= is present"""
3857
3858 parser_signature = Sig(prog='PROG', usage='%(prog)s FOO')
3859 argument_signatures = []
3860 argument_group_signatures = []
3861 usage = ('''\
3862 usage: PROG FOO
3863 ''')
3864 help = usage + '''\
3865
3866 optional arguments:
3867 -h, --help show this help message and exit
3868 '''
3869 version = ''
3870
3871
3872class TestHelpVariableExpansionNoArguments(HelpTestCase):
3873 """Test that variables are expanded properly with no arguments"""
3874
3875 parser_signature = Sig(prog='PROG', add_help=False)
3876 argument_signatures = []
3877 argument_group_signatures = []
3878 usage = ('''\
3879 usage: PROG
3880 ''')
3881 help = usage
3882 version = ''
3883
3884
3885class TestHelpSuppressUsage(HelpTestCase):
3886 """Test that items can be suppressed in usage messages"""
3887
3888 parser_signature = Sig(prog='PROG', usage=argparse.SUPPRESS)
3889 argument_signatures = [
3890 Sig('--foo', help='foo help'),
3891 Sig('spam', help='spam help'),
3892 ]
3893 argument_group_signatures = []
3894 help = '''\
3895 positional arguments:
3896 spam spam help
3897
3898 optional arguments:
3899 -h, --help show this help message and exit
3900 --foo FOO foo help
3901 '''
3902 usage = ''
3903 version = ''
3904
3905
3906class TestHelpSuppressOptional(HelpTestCase):
3907 """Test that optional arguments can be suppressed in help messages"""
3908
3909 parser_signature = Sig(prog='PROG', add_help=False)
3910 argument_signatures = [
3911 Sig('--foo', help=argparse.SUPPRESS),
3912 Sig('spam', help='spam help'),
3913 ]
3914 argument_group_signatures = []
3915 usage = '''\
3916 usage: PROG spam
3917 '''
3918 help = usage + '''\
3919
3920 positional arguments:
3921 spam spam help
3922 '''
3923 version = ''
3924
3925
3926class TestHelpSuppressOptionalGroup(HelpTestCase):
3927 """Test that optional groups can be suppressed in help messages"""
3928
3929 parser_signature = Sig(prog='PROG')
3930 argument_signatures = [
3931 Sig('--foo', help='foo help'),
3932 Sig('spam', help='spam help'),
3933 ]
3934 argument_group_signatures = [
3935 (Sig('group'), [Sig('--bar', help=argparse.SUPPRESS)]),
3936 ]
3937 usage = '''\
3938 usage: PROG [-h] [--foo FOO] spam
3939 '''
3940 help = usage + '''\
3941
3942 positional arguments:
3943 spam spam help
3944
3945 optional arguments:
3946 -h, --help show this help message and exit
3947 --foo FOO foo help
3948 '''
3949 version = ''
3950
3951
3952class TestHelpSuppressPositional(HelpTestCase):
3953 """Test that positional arguments can be suppressed in help messages"""
3954
3955 parser_signature = Sig(prog='PROG')
3956 argument_signatures = [
3957 Sig('--foo', help='foo help'),
3958 Sig('spam', help=argparse.SUPPRESS),
3959 ]
3960 argument_group_signatures = []
3961 usage = '''\
3962 usage: PROG [-h] [--foo FOO]
3963 '''
3964 help = usage + '''\
3965
3966 optional arguments:
3967 -h, --help show this help message and exit
3968 --foo FOO foo help
3969 '''
3970 version = ''
3971
3972
3973class TestHelpRequiredOptional(HelpTestCase):
3974 """Test that required options don't look optional"""
3975
3976 parser_signature = Sig(prog='PROG')
3977 argument_signatures = [
3978 Sig('--foo', required=True, help='foo help'),
3979 ]
3980 argument_group_signatures = []
3981 usage = '''\
3982 usage: PROG [-h] --foo FOO
3983 '''
3984 help = usage + '''\
3985
3986 optional arguments:
3987 -h, --help show this help message and exit
3988 --foo FOO foo help
3989 '''
3990 version = ''
3991
3992
3993class TestHelpAlternatePrefixChars(HelpTestCase):
3994 """Test that options display with different prefix characters"""
3995
3996 parser_signature = Sig(prog='PROG', prefix_chars='^;', add_help=False)
3997 argument_signatures = [
3998 Sig('^^foo', action='store_true', help='foo help'),
3999 Sig(';b', ';;bar', help='bar help'),
4000 ]
4001 argument_group_signatures = []
4002 usage = '''\
4003 usage: PROG [^^foo] [;b BAR]
4004 '''
4005 help = usage + '''\
4006
4007 optional arguments:
4008 ^^foo foo help
4009 ;b BAR, ;;bar BAR bar help
4010 '''
4011 version = ''
4012
4013
4014class TestHelpNoHelpOptional(HelpTestCase):
4015 """Test that the --help argument can be suppressed help messages"""
4016
4017 parser_signature = Sig(prog='PROG', add_help=False)
4018 argument_signatures = [
4019 Sig('--foo', help='foo help'),
4020 Sig('spam', help='spam help'),
4021 ]
4022 argument_group_signatures = []
4023 usage = '''\
4024 usage: PROG [--foo FOO] spam
4025 '''
4026 help = usage + '''\
4027
4028 positional arguments:
4029 spam spam help
4030
4031 optional arguments:
4032 --foo FOO foo help
4033 '''
4034 version = ''
4035
4036
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004037class TestHelpNone(HelpTestCase):
4038 """Test that no errors occur if no help is specified"""
4039
4040 parser_signature = Sig(prog='PROG')
4041 argument_signatures = [
4042 Sig('--foo'),
4043 Sig('spam'),
4044 ]
4045 argument_group_signatures = []
4046 usage = '''\
4047 usage: PROG [-h] [--foo FOO] spam
4048 '''
4049 help = usage + '''\
4050
4051 positional arguments:
4052 spam
4053
4054 optional arguments:
4055 -h, --help show this help message and exit
4056 --foo FOO
4057 '''
4058 version = ''
4059
4060
4061class TestHelpTupleMetavar(HelpTestCase):
4062 """Test specifying metavar as a tuple"""
4063
4064 parser_signature = Sig(prog='PROG')
4065 argument_signatures = [
4066 Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
4067 Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
4068 Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
4069 Sig('-z', help='z', nargs='?', metavar=('Z1', )),
4070 ]
4071 argument_group_signatures = []
4072 usage = '''\
4073 usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
4074[-z [Z1]]
4075 '''
4076 help = usage + '''\
4077
4078 optional arguments:
4079 -h, --help show this help message and exit
4080 -w W1 [W2 ...] w
4081 -x [X1 [X2 ...]] x
4082 -y Y1 Y2 Y3 y
4083 -z [Z1] z
4084 '''
4085 version = ''
4086
4087
4088class TestHelpRawText(HelpTestCase):
4089 """Test the RawTextHelpFormatter"""
4090
4091 parser_signature = Sig(
4092 prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
4093 description='Keep the formatting\n'
4094 ' exactly as it is written\n'
4095 '\n'
4096 'here\n')
4097
4098 argument_signatures = [
4099 Sig('--foo', help=' foo help should also\n'
4100 'appear as given here'),
4101 Sig('spam', help='spam help'),
4102 ]
4103 argument_group_signatures = [
4104 (Sig('title', description=' This text\n'
4105 ' should be indented\n'
4106 ' exactly like it is here\n'),
4107 [Sig('--bar', help='bar help')]),
4108 ]
4109 usage = '''\
4110 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
4111 '''
4112 help = usage + '''\
4113
4114 Keep the formatting
4115 exactly as it is written
4116
4117 here
4118
4119 positional arguments:
4120 spam spam help
4121
4122 optional arguments:
4123 -h, --help show this help message and exit
4124 --foo FOO foo help should also
4125 appear as given here
4126
4127 title:
4128 This text
4129 should be indented
4130 exactly like it is here
4131
4132 --bar BAR bar help
4133 '''
4134 version = ''
4135
4136
4137class TestHelpRawDescription(HelpTestCase):
4138 """Test the RawTextHelpFormatter"""
4139
4140 parser_signature = Sig(
4141 prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
4142 description='Keep the formatting\n'
4143 ' exactly as it is written\n'
4144 '\n'
4145 'here\n')
4146
4147 argument_signatures = [
4148 Sig('--foo', help=' foo help should not\n'
4149 ' retain this odd formatting'),
4150 Sig('spam', help='spam help'),
4151 ]
4152 argument_group_signatures = [
4153 (Sig('title', description=' This text\n'
4154 ' should be indented\n'
4155 ' exactly like it is here\n'),
4156 [Sig('--bar', help='bar help')]),
4157 ]
4158 usage = '''\
4159 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
4160 '''
4161 help = usage + '''\
4162
4163 Keep the formatting
4164 exactly as it is written
4165
4166 here
4167
4168 positional arguments:
4169 spam spam help
4170
4171 optional arguments:
4172 -h, --help show this help message and exit
4173 --foo FOO foo help should not retain this odd formatting
4174
4175 title:
4176 This text
4177 should be indented
4178 exactly like it is here
4179
4180 --bar BAR bar help
4181 '''
4182 version = ''
4183
4184
4185class TestHelpArgumentDefaults(HelpTestCase):
4186 """Test the ArgumentDefaultsHelpFormatter"""
4187
4188 parser_signature = Sig(
4189 prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
4190 description='description')
4191
4192 argument_signatures = [
4193 Sig('--foo', help='foo help - oh and by the way, %(default)s'),
4194 Sig('--bar', action='store_true', help='bar help'),
4195 Sig('spam', help='spam help'),
4196 Sig('badger', nargs='?', default='wooden', help='badger help'),
4197 ]
4198 argument_group_signatures = [
4199 (Sig('title', description='description'),
4200 [Sig('--baz', type=int, default=42, help='baz help')]),
4201 ]
4202 usage = '''\
4203 usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
4204 '''
4205 help = usage + '''\
4206
4207 description
4208
4209 positional arguments:
4210 spam spam help
4211 badger badger help (default: wooden)
4212
4213 optional arguments:
4214 -h, --help show this help message and exit
4215 --foo FOO foo help - oh and by the way, None
4216 --bar bar help (default: False)
4217
4218 title:
4219 description
4220
4221 --baz BAZ baz help (default: 42)
4222 '''
4223 version = ''
4224
Steven Bethard50fe5932010-05-24 03:47:38 +00004225class TestHelpVersionAction(HelpTestCase):
4226 """Test the default help for the version action"""
4227
4228 parser_signature = Sig(prog='PROG', description='description')
4229 argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
4230 argument_group_signatures = []
4231 usage = '''\
4232 usage: PROG [-h] [-V]
4233 '''
4234 help = usage + '''\
4235
4236 description
4237
4238 optional arguments:
4239 -h, --help show this help message and exit
4240 -V, --version show program's version number and exit
4241 '''
4242 version = ''
4243
Berker Peksagecb75e22015-04-10 16:11:12 +03004244
4245class TestHelpVersionActionSuppress(HelpTestCase):
4246 """Test that the --version argument can be suppressed in help messages"""
4247
4248 parser_signature = Sig(prog='PROG')
4249 argument_signatures = [
4250 Sig('-v', '--version', action='version', version='1.0',
4251 help=argparse.SUPPRESS),
4252 Sig('--foo', help='foo help'),
4253 Sig('spam', help='spam help'),
4254 ]
4255 argument_group_signatures = []
4256 usage = '''\
4257 usage: PROG [-h] [--foo FOO] spam
4258 '''
4259 help = usage + '''\
4260
4261 positional arguments:
4262 spam spam help
4263
4264 optional arguments:
4265 -h, --help show this help message and exit
4266 --foo FOO foo help
4267 '''
4268
4269
Steven Bethard8a6a1982011-03-27 13:53:53 +02004270class TestHelpSubparsersOrdering(HelpTestCase):
4271 """Test ordering of subcommands in help matches the code"""
4272 parser_signature = Sig(prog='PROG',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004273 description='display some subcommands')
4274 argument_signatures = [Sig('-v', '--version', action='version', version='0.1')]
Steven Bethard8a6a1982011-03-27 13:53:53 +02004275
4276 subparsers_signatures = [Sig(name=name)
4277 for name in ('a', 'b', 'c', 'd', 'e')]
4278
4279 usage = '''\
4280 usage: PROG [-h] [-v] {a,b,c,d,e} ...
4281 '''
4282
4283 help = usage + '''\
4284
4285 display some subcommands
4286
4287 positional arguments:
4288 {a,b,c,d,e}
4289
4290 optional arguments:
4291 -h, --help show this help message and exit
4292 -v, --version show program's version number and exit
4293 '''
4294
4295 version = '''\
4296 0.1
4297 '''
4298
4299class TestHelpSubparsersWithHelpOrdering(HelpTestCase):
4300 """Test ordering of subcommands in help matches the code"""
4301 parser_signature = Sig(prog='PROG',
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004302 description='display some subcommands')
4303 argument_signatures = [Sig('-v', '--version', action='version', version='0.1')]
Steven Bethard8a6a1982011-03-27 13:53:53 +02004304
4305 subcommand_data = (('a', 'a subcommand help'),
4306 ('b', 'b subcommand help'),
4307 ('c', 'c subcommand help'),
4308 ('d', 'd subcommand help'),
4309 ('e', 'e subcommand help'),
4310 )
4311
4312 subparsers_signatures = [Sig(name=name, help=help)
4313 for name, help in subcommand_data]
4314
4315 usage = '''\
4316 usage: PROG [-h] [-v] {a,b,c,d,e} ...
4317 '''
4318
4319 help = usage + '''\
4320
4321 display some subcommands
4322
4323 positional arguments:
4324 {a,b,c,d,e}
4325 a a subcommand help
4326 b b subcommand help
4327 c c subcommand help
4328 d d subcommand help
4329 e e subcommand help
4330
4331 optional arguments:
4332 -h, --help show this help message and exit
4333 -v, --version show program's version number and exit
4334 '''
4335
4336 version = '''\
4337 0.1
4338 '''
4339
4340
Steven Bethard0331e902011-03-26 14:48:04 +01004341
4342class TestHelpMetavarTypeFormatter(HelpTestCase):
Steven Bethard0331e902011-03-26 14:48:04 +01004343
4344 def custom_type(string):
4345 return string
4346
4347 parser_signature = Sig(prog='PROG', description='description',
4348 formatter_class=argparse.MetavarTypeHelpFormatter)
4349 argument_signatures = [Sig('a', type=int),
4350 Sig('-b', type=custom_type),
4351 Sig('-c', type=float, metavar='SOME FLOAT')]
4352 argument_group_signatures = []
4353 usage = '''\
4354 usage: PROG [-h] [-b custom_type] [-c SOME FLOAT] int
4355 '''
4356 help = usage + '''\
4357
4358 description
4359
4360 positional arguments:
4361 int
4362
4363 optional arguments:
4364 -h, --help show this help message and exit
4365 -b custom_type
4366 -c SOME FLOAT
4367 '''
4368 version = ''
4369
4370
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004371# =====================================
4372# Optional/Positional constructor tests
4373# =====================================
4374
4375class TestInvalidArgumentConstructors(TestCase):
4376 """Test a bunch of invalid Argument constructors"""
4377
4378 def assertTypeError(self, *args, **kwargs):
4379 parser = argparse.ArgumentParser()
4380 self.assertRaises(TypeError, parser.add_argument,
4381 *args, **kwargs)
4382
4383 def assertValueError(self, *args, **kwargs):
4384 parser = argparse.ArgumentParser()
4385 self.assertRaises(ValueError, parser.add_argument,
4386 *args, **kwargs)
4387
4388 def test_invalid_keyword_arguments(self):
4389 self.assertTypeError('-x', bar=None)
4390 self.assertTypeError('-y', callback='foo')
4391 self.assertTypeError('-y', callback_args=())
4392 self.assertTypeError('-y', callback_kwargs={})
4393
4394 def test_missing_destination(self):
4395 self.assertTypeError()
4396 for action in ['append', 'store']:
4397 self.assertTypeError(action=action)
4398
4399 def test_invalid_option_strings(self):
4400 self.assertValueError('--')
4401 self.assertValueError('---')
4402
4403 def test_invalid_type(self):
4404 self.assertValueError('--foo', type='int')
Steven Bethard7cb20a82011-04-04 01:53:02 +02004405 self.assertValueError('--foo', type=(int, float))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004406
4407 def test_invalid_action(self):
4408 self.assertValueError('-x', action='foo')
4409 self.assertValueError('foo', action='baz')
Steven Bethard7cb20a82011-04-04 01:53:02 +02004410 self.assertValueError('--foo', action=('store', 'append'))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004411 parser = argparse.ArgumentParser()
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004412 with self.assertRaises(ValueError) as cm:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004413 parser.add_argument("--foo", action="store-true")
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004414 self.assertIn('unknown action', str(cm.exception))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004415
4416 def test_multiple_dest(self):
4417 parser = argparse.ArgumentParser()
4418 parser.add_argument(dest='foo')
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004419 with self.assertRaises(ValueError) as cm:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004420 parser.add_argument('bar', dest='baz')
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004421 self.assertIn('dest supplied twice for positional argument',
4422 str(cm.exception))
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004423
4424 def test_no_argument_actions(self):
4425 for action in ['store_const', 'store_true', 'store_false',
4426 'append_const', 'count']:
4427 for attrs in [dict(type=int), dict(nargs='+'),
4428 dict(choices='ab')]:
4429 self.assertTypeError('-x', action=action, **attrs)
4430
4431 def test_no_argument_no_const_actions(self):
4432 # options with zero arguments
4433 for action in ['store_true', 'store_false', 'count']:
4434
4435 # const is always disallowed
4436 self.assertTypeError('-x', const='foo', action=action)
4437
4438 # nargs is always disallowed
4439 self.assertTypeError('-x', nargs='*', action=action)
4440
4441 def test_more_than_one_argument_actions(self):
4442 for action in ['store', 'append']:
4443
4444 # nargs=0 is disallowed
4445 self.assertValueError('-x', nargs=0, action=action)
4446 self.assertValueError('spam', nargs=0, action=action)
4447
4448 # const is disallowed with non-optional arguments
4449 for nargs in [1, '*', '+']:
4450 self.assertValueError('-x', const='foo',
4451 nargs=nargs, action=action)
4452 self.assertValueError('spam', const='foo',
4453 nargs=nargs, action=action)
4454
4455 def test_required_const_actions(self):
4456 for action in ['store_const', 'append_const']:
4457
4458 # nargs is always disallowed
4459 self.assertTypeError('-x', nargs='+', action=action)
4460
4461 def test_parsers_action_missing_params(self):
4462 self.assertTypeError('command', action='parsers')
4463 self.assertTypeError('command', action='parsers', prog='PROG')
4464 self.assertTypeError('command', action='parsers',
4465 parser_class=argparse.ArgumentParser)
4466
4467 def test_required_positional(self):
4468 self.assertTypeError('foo', required=True)
4469
4470 def test_user_defined_action(self):
4471
4472 class Success(Exception):
4473 pass
4474
4475 class Action(object):
4476
4477 def __init__(self,
4478 option_strings,
4479 dest,
4480 const,
4481 default,
4482 required=False):
4483 if dest == 'spam':
4484 if const is Success:
4485 if default is Success:
4486 raise Success()
4487
4488 def __call__(self, *args, **kwargs):
4489 pass
4490
4491 parser = argparse.ArgumentParser()
4492 self.assertRaises(Success, parser.add_argument, '--spam',
4493 action=Action, default=Success, const=Success)
4494 self.assertRaises(Success, parser.add_argument, 'spam',
4495 action=Action, default=Success, const=Success)
4496
4497# ================================
4498# Actions returned by add_argument
4499# ================================
4500
4501class TestActionsReturned(TestCase):
4502
4503 def test_dest(self):
4504 parser = argparse.ArgumentParser()
4505 action = parser.add_argument('--foo')
4506 self.assertEqual(action.dest, 'foo')
4507 action = parser.add_argument('-b', '--bar')
4508 self.assertEqual(action.dest, 'bar')
4509 action = parser.add_argument('-x', '-y')
4510 self.assertEqual(action.dest, 'x')
4511
4512 def test_misc(self):
4513 parser = argparse.ArgumentParser()
4514 action = parser.add_argument('--foo', nargs='?', const=42,
4515 default=84, type=int, choices=[1, 2],
4516 help='FOO', metavar='BAR', dest='baz')
4517 self.assertEqual(action.nargs, '?')
4518 self.assertEqual(action.const, 42)
4519 self.assertEqual(action.default, 84)
4520 self.assertEqual(action.type, int)
4521 self.assertEqual(action.choices, [1, 2])
4522 self.assertEqual(action.help, 'FOO')
4523 self.assertEqual(action.metavar, 'BAR')
4524 self.assertEqual(action.dest, 'baz')
4525
4526
4527# ================================
4528# Argument conflict handling tests
4529# ================================
4530
4531class TestConflictHandling(TestCase):
4532
4533 def test_bad_type(self):
4534 self.assertRaises(ValueError, argparse.ArgumentParser,
4535 conflict_handler='foo')
4536
4537 def test_conflict_error(self):
4538 parser = argparse.ArgumentParser()
4539 parser.add_argument('-x')
4540 self.assertRaises(argparse.ArgumentError,
4541 parser.add_argument, '-x')
4542 parser.add_argument('--spam')
4543 self.assertRaises(argparse.ArgumentError,
4544 parser.add_argument, '--spam')
4545
4546 def test_resolve_error(self):
4547 get_parser = argparse.ArgumentParser
4548 parser = get_parser(prog='PROG', conflict_handler='resolve')
4549
4550 parser.add_argument('-x', help='OLD X')
4551 parser.add_argument('-x', help='NEW X')
4552 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4553 usage: PROG [-h] [-x X]
4554
4555 optional arguments:
4556 -h, --help show this help message and exit
4557 -x X NEW X
4558 '''))
4559
4560 parser.add_argument('--spam', metavar='OLD_SPAM')
4561 parser.add_argument('--spam', metavar='NEW_SPAM')
4562 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4563 usage: PROG [-h] [-x X] [--spam NEW_SPAM]
4564
4565 optional arguments:
4566 -h, --help show this help message and exit
4567 -x X NEW X
4568 --spam NEW_SPAM
4569 '''))
4570
4571
4572# =============================
4573# Help and Version option tests
4574# =============================
4575
4576class TestOptionalsHelpVersionActions(TestCase):
4577 """Test the help and version actions"""
4578
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004579 def assertPrintHelpExit(self, parser, args_str):
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004580 with self.assertRaises(ArgumentParserError) as cm:
4581 parser.parse_args(args_str.split())
4582 self.assertEqual(parser.format_help(), cm.exception.stdout)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004583
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004584 def assertArgumentParserError(self, parser, *args):
4585 self.assertRaises(ArgumentParserError, parser.parse_args, args)
4586
4587 def test_version(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004588 parser = ErrorRaisingArgumentParser()
4589 parser.add_argument('-v', '--version', action='version', version='1.0')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004590 self.assertPrintHelpExit(parser, '-h')
4591 self.assertPrintHelpExit(parser, '--help')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004592 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004593
4594 def test_version_format(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004595 parser = ErrorRaisingArgumentParser(prog='PPP')
4596 parser.add_argument('-v', '--version', action='version', version='%(prog)s 3.5')
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004597 with self.assertRaises(ArgumentParserError) as cm:
4598 parser.parse_args(['-v'])
4599 self.assertEqual('PPP 3.5\n', cm.exception.stdout)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004600
4601 def test_version_no_help(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004602 parser = ErrorRaisingArgumentParser(add_help=False)
4603 parser.add_argument('-v', '--version', action='version', version='1.0')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004604 self.assertArgumentParserError(parser, '-h')
4605 self.assertArgumentParserError(parser, '--help')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004606 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004607
4608 def test_version_action(self):
4609 parser = ErrorRaisingArgumentParser(prog='XXX')
4610 parser.add_argument('-V', action='version', version='%(prog)s 3.7')
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004611 with self.assertRaises(ArgumentParserError) as cm:
4612 parser.parse_args(['-V'])
4613 self.assertEqual('XXX 3.7\n', cm.exception.stdout)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004614
4615 def test_no_help(self):
4616 parser = ErrorRaisingArgumentParser(add_help=False)
4617 self.assertArgumentParserError(parser, '-h')
4618 self.assertArgumentParserError(parser, '--help')
4619 self.assertArgumentParserError(parser, '-v')
4620 self.assertArgumentParserError(parser, '--version')
4621
4622 def test_alternate_help_version(self):
4623 parser = ErrorRaisingArgumentParser()
4624 parser.add_argument('-x', action='help')
4625 parser.add_argument('-y', action='version')
4626 self.assertPrintHelpExit(parser, '-x')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004627 self.assertArgumentParserError(parser, '-v')
4628 self.assertArgumentParserError(parser, '--version')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004629 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004630
4631 def test_help_version_extra_arguments(self):
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004632 parser = ErrorRaisingArgumentParser()
4633 parser.add_argument('--version', action='version', version='1.0')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004634 parser.add_argument('-x', action='store_true')
4635 parser.add_argument('y')
4636
4637 # try all combinations of valid prefixes and suffixes
4638 valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
4639 valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
4640 for prefix in valid_prefixes:
4641 for suffix in valid_suffixes:
4642 format = '%s %%s %s' % (prefix, suffix)
4643 self.assertPrintHelpExit(parser, format % '-h')
4644 self.assertPrintHelpExit(parser, format % '--help')
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004645 self.assertRaises(AttributeError, getattr, parser, 'format_version')
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004646
4647
4648# ======================
4649# str() and repr() tests
4650# ======================
4651
4652class TestStrings(TestCase):
4653 """Test str() and repr() on Optionals and Positionals"""
4654
4655 def assertStringEqual(self, obj, result_string):
4656 for func in [str, repr]:
4657 self.assertEqual(func(obj), result_string)
4658
4659 def test_optional(self):
4660 option = argparse.Action(
4661 option_strings=['--foo', '-a', '-b'],
4662 dest='b',
4663 type='int',
4664 nargs='+',
4665 default=42,
4666 choices=[1, 2, 3],
4667 help='HELP',
4668 metavar='METAVAR')
4669 string = (
4670 "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
4671 "nargs='+', const=None, default=42, type='int', "
4672 "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
4673 self.assertStringEqual(option, string)
4674
4675 def test_argument(self):
4676 argument = argparse.Action(
4677 option_strings=[],
4678 dest='x',
4679 type=float,
4680 nargs='?',
4681 default=2.5,
4682 choices=[0.5, 1.5, 2.5],
4683 help='H HH H',
4684 metavar='MV MV MV')
4685 string = (
4686 "Action(option_strings=[], dest='x', nargs='?', "
4687 "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
4688 "help='H HH H', metavar='MV MV MV')" % float)
4689 self.assertStringEqual(argument, string)
4690
4691 def test_namespace(self):
4692 ns = argparse.Namespace(foo=42, bar='spam')
4693 string = "Namespace(bar='spam', foo=42)"
4694 self.assertStringEqual(ns, string)
4695
Berker Peksag76b17142015-07-29 23:51:47 +03004696 def test_namespace_starkwargs_notidentifier(self):
4697 ns = argparse.Namespace(**{'"': 'quote'})
4698 string = """Namespace(**{'"': 'quote'})"""
4699 self.assertStringEqual(ns, string)
4700
4701 def test_namespace_kwargs_and_starkwargs_notidentifier(self):
4702 ns = argparse.Namespace(a=1, **{'"': 'quote'})
4703 string = """Namespace(a=1, **{'"': 'quote'})"""
4704 self.assertStringEqual(ns, string)
4705
4706 def test_namespace_starkwargs_identifier(self):
4707 ns = argparse.Namespace(**{'valid': True})
4708 string = "Namespace(valid=True)"
4709 self.assertStringEqual(ns, string)
4710
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004711 def test_parser(self):
4712 parser = argparse.ArgumentParser(prog='PROG')
4713 string = (
4714 "ArgumentParser(prog='PROG', usage=None, description=None, "
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02004715 "formatter_class=%r, conflict_handler='error', "
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004716 "add_help=True)" % argparse.HelpFormatter)
4717 self.assertStringEqual(parser, string)
4718
4719# ===============
4720# Namespace tests
4721# ===============
4722
4723class TestNamespace(TestCase):
4724
4725 def test_constructor(self):
4726 ns = argparse.Namespace()
4727 self.assertRaises(AttributeError, getattr, ns, 'x')
4728
4729 ns = argparse.Namespace(a=42, b='spam')
4730 self.assertEqual(ns.a, 42)
4731 self.assertEqual(ns.b, 'spam')
4732
4733 def test_equality(self):
4734 ns1 = argparse.Namespace(a=1, b=2)
4735 ns2 = argparse.Namespace(b=2, a=1)
4736 ns3 = argparse.Namespace(a=1)
4737 ns4 = argparse.Namespace(b=2)
4738
4739 self.assertEqual(ns1, ns2)
4740 self.assertNotEqual(ns1, ns3)
4741 self.assertNotEqual(ns1, ns4)
4742 self.assertNotEqual(ns2, ns3)
4743 self.assertNotEqual(ns2, ns4)
4744 self.assertTrue(ns1 != ns3)
4745 self.assertTrue(ns1 != ns4)
4746 self.assertTrue(ns2 != ns3)
4747 self.assertTrue(ns2 != ns4)
4748
Berker Peksagc16387b2016-09-28 17:21:52 +03004749 def test_equality_returns_notimplemented(self):
Raymond Hettingerdea46ec2014-05-26 00:43:27 -07004750 # See issue 21481
4751 ns = argparse.Namespace(a=1, b=2)
4752 self.assertIs(ns.__eq__(None), NotImplemented)
4753 self.assertIs(ns.__ne__(None), NotImplemented)
4754
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004755
4756# ===================
4757# File encoding tests
4758# ===================
4759
4760class TestEncoding(TestCase):
4761
4762 def _test_module_encoding(self, path):
4763 path, _ = os.path.splitext(path)
4764 path += ".py"
Victor Stinner272d8882017-06-16 08:59:01 +02004765 with open(path, 'r', encoding='utf-8') as f:
Antoine Pitroub86680e2010-10-14 21:15:17 +00004766 f.read()
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004767
4768 def test_argparse_module_encoding(self):
4769 self._test_module_encoding(argparse.__file__)
4770
4771 def test_test_argparse_module_encoding(self):
4772 self._test_module_encoding(__file__)
4773
4774# ===================
4775# ArgumentError tests
4776# ===================
4777
4778class TestArgumentError(TestCase):
4779
4780 def test_argument_error(self):
4781 msg = "my error here"
4782 error = argparse.ArgumentError(None, msg)
4783 self.assertEqual(str(error), msg)
4784
4785# =======================
4786# ArgumentTypeError tests
4787# =======================
4788
R. David Murray722b5fd2010-11-20 03:48:58 +00004789class TestArgumentTypeError(TestCase):
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004790
4791 def test_argument_type_error(self):
4792
4793 def spam(string):
4794 raise argparse.ArgumentTypeError('spam!')
4795
4796 parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
4797 parser.add_argument('x', type=spam)
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004798 with self.assertRaises(ArgumentParserError) as cm:
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004799 parser.parse_args(['XXX'])
Berker Peksag1c5f56a2014-07-06 09:33:20 +03004800 self.assertEqual('usage: PROG x\nPROG: error: argument x: spam!\n',
4801 cm.exception.stderr)
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004802
R David Murrayf97c59a2011-06-09 12:34:07 -04004803# =========================
4804# MessageContentError tests
4805# =========================
4806
4807class TestMessageContentError(TestCase):
4808
4809 def test_missing_argument_name_in_message(self):
4810 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4811 parser.add_argument('req_pos', type=str)
4812 parser.add_argument('-req_opt', type=int, required=True)
4813 parser.add_argument('need_one', type=str, nargs='+')
4814
4815 with self.assertRaises(ArgumentParserError) as cm:
4816 parser.parse_args([])
4817 msg = str(cm.exception)
4818 self.assertRegex(msg, 'req_pos')
4819 self.assertRegex(msg, 'req_opt')
4820 self.assertRegex(msg, 'need_one')
4821 with self.assertRaises(ArgumentParserError) as cm:
4822 parser.parse_args(['myXargument'])
4823 msg = str(cm.exception)
4824 self.assertNotIn(msg, 'req_pos')
4825 self.assertRegex(msg, 'req_opt')
4826 self.assertRegex(msg, 'need_one')
4827 with self.assertRaises(ArgumentParserError) as cm:
4828 parser.parse_args(['myXargument', '-req_opt=1'])
4829 msg = str(cm.exception)
4830 self.assertNotIn(msg, 'req_pos')
4831 self.assertNotIn(msg, 'req_opt')
4832 self.assertRegex(msg, 'need_one')
4833
4834 def test_optional_optional_not_in_message(self):
4835 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4836 parser.add_argument('req_pos', type=str)
4837 parser.add_argument('--req_opt', type=int, required=True)
4838 parser.add_argument('--opt_opt', type=bool, nargs='?',
4839 default=True)
4840 with self.assertRaises(ArgumentParserError) as cm:
4841 parser.parse_args([])
4842 msg = str(cm.exception)
4843 self.assertRegex(msg, 'req_pos')
4844 self.assertRegex(msg, 'req_opt')
4845 self.assertNotIn(msg, 'opt_opt')
4846 with self.assertRaises(ArgumentParserError) as cm:
4847 parser.parse_args(['--req_opt=1'])
4848 msg = str(cm.exception)
4849 self.assertRegex(msg, 'req_pos')
4850 self.assertNotIn(msg, 'req_opt')
4851 self.assertNotIn(msg, 'opt_opt')
4852
4853 def test_optional_positional_not_in_message(self):
4854 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
4855 parser.add_argument('req_pos')
4856 parser.add_argument('optional_positional', nargs='?', default='eggs')
4857 with self.assertRaises(ArgumentParserError) as cm:
4858 parser.parse_args([])
4859 msg = str(cm.exception)
4860 self.assertRegex(msg, 'req_pos')
4861 self.assertNotIn(msg, 'optional_positional')
4862
4863
R David Murray6fb8fb12012-08-31 22:45:20 -04004864# ================================================
4865# Check that the type function is called only once
4866# ================================================
4867
4868class TestTypeFunctionCallOnlyOnce(TestCase):
4869
4870 def test_type_function_call_only_once(self):
4871 def spam(string_to_convert):
4872 self.assertEqual(string_to_convert, 'spam!')
4873 return 'foo_converted'
4874
4875 parser = argparse.ArgumentParser()
4876 parser.add_argument('--foo', type=spam, default='bar')
4877 args = parser.parse_args('--foo spam!'.split())
4878 self.assertEqual(NS(foo='foo_converted'), args)
4879
Barry Warsaweaae1b72012-09-12 14:34:50 -04004880# ==================================================================
4881# Check semantics regarding the default argument and type conversion
4882# ==================================================================
R David Murray6fb8fb12012-08-31 22:45:20 -04004883
Barry Warsaweaae1b72012-09-12 14:34:50 -04004884class TestTypeFunctionCalledOnDefault(TestCase):
R David Murray6fb8fb12012-08-31 22:45:20 -04004885
4886 def test_type_function_call_with_non_string_default(self):
4887 def spam(int_to_convert):
4888 self.assertEqual(int_to_convert, 0)
4889 return 'foo_converted'
4890
4891 parser = argparse.ArgumentParser()
4892 parser.add_argument('--foo', type=spam, default=0)
4893 args = parser.parse_args([])
Barry Warsaweaae1b72012-09-12 14:34:50 -04004894 # foo should *not* be converted because its default is not a string.
4895 self.assertEqual(NS(foo=0), args)
4896
4897 def test_type_function_call_with_string_default(self):
4898 def spam(int_to_convert):
4899 return 'foo_converted'
4900
4901 parser = argparse.ArgumentParser()
4902 parser.add_argument('--foo', type=spam, default='0')
4903 args = parser.parse_args([])
4904 # foo is converted because its default is a string.
R David Murray6fb8fb12012-08-31 22:45:20 -04004905 self.assertEqual(NS(foo='foo_converted'), args)
4906
Barry Warsaweaae1b72012-09-12 14:34:50 -04004907 def test_no_double_type_conversion_of_default(self):
4908 def extend(str_to_convert):
4909 return str_to_convert + '*'
4910
4911 parser = argparse.ArgumentParser()
4912 parser.add_argument('--test', type=extend, default='*')
4913 args = parser.parse_args([])
4914 # The test argument will be two stars, one coming from the default
4915 # value and one coming from the type conversion being called exactly
4916 # once.
4917 self.assertEqual(NS(test='**'), args)
4918
Barry Warsaw4b2f9e92012-09-11 22:38:47 -04004919 def test_issue_15906(self):
4920 # Issue #15906: When action='append', type=str, default=[] are
4921 # providing, the dest value was the string representation "[]" when it
4922 # should have been an empty list.
4923 parser = argparse.ArgumentParser()
4924 parser.add_argument('--test', dest='test', type=str,
4925 default=[], action='append')
4926 args = parser.parse_args([])
4927 self.assertEqual(args.test, [])
4928
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004929# ======================
4930# parse_known_args tests
4931# ======================
4932
4933class TestParseKnownArgs(TestCase):
4934
R David Murrayb5228282012-09-08 12:08:01 -04004935 def test_arguments_tuple(self):
4936 parser = argparse.ArgumentParser()
4937 parser.parse_args(())
4938
4939 def test_arguments_list(self):
4940 parser = argparse.ArgumentParser()
4941 parser.parse_args([])
4942
4943 def test_arguments_tuple_positional(self):
4944 parser = argparse.ArgumentParser()
4945 parser.add_argument('x')
4946 parser.parse_args(('x',))
4947
4948 def test_arguments_list_positional(self):
4949 parser = argparse.ArgumentParser()
4950 parser.add_argument('x')
4951 parser.parse_args(['x'])
4952
Benjamin Peterson698a18a2010-03-02 22:34:37 +00004953 def test_optionals(self):
4954 parser = argparse.ArgumentParser()
4955 parser.add_argument('--foo')
4956 args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
4957 self.assertEqual(NS(foo='F'), args)
4958 self.assertEqual(['--bar', '--baz'], extras)
4959
4960 def test_mixed(self):
4961 parser = argparse.ArgumentParser()
4962 parser.add_argument('-v', nargs='?', const=1, type=int)
4963 parser.add_argument('--spam', action='store_false')
4964 parser.add_argument('badger')
4965
4966 argv = ["B", "C", "--foo", "-v", "3", "4"]
4967 args, extras = parser.parse_known_args(argv)
4968 self.assertEqual(NS(v=3, spam=True, badger="B"), args)
4969 self.assertEqual(["C", "--foo", "4"], extras)
4970
R. David Murray0f6b9d22017-09-06 20:25:40 -04004971# ===========================
4972# parse_intermixed_args tests
4973# ===========================
4974
4975class TestIntermixedArgs(TestCase):
4976 def test_basic(self):
4977 # test parsing intermixed optionals and positionals
4978 parser = argparse.ArgumentParser(prog='PROG')
4979 parser.add_argument('--foo', dest='foo')
4980 bar = parser.add_argument('--bar', dest='bar', required=True)
4981 parser.add_argument('cmd')
4982 parser.add_argument('rest', nargs='*', type=int)
4983 argv = 'cmd --foo x 1 --bar y 2 3'.split()
4984 args = parser.parse_intermixed_args(argv)
4985 # rest gets [1,2,3] despite the foo and bar strings
4986 self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[1, 2, 3]), args)
4987
4988 args, extras = parser.parse_known_args(argv)
4989 # cannot parse the '1,2,3'
4990 self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[]), args)
4991 self.assertEqual(["1", "2", "3"], extras)
4992
4993 argv = 'cmd --foo x 1 --error 2 --bar y 3'.split()
4994 args, extras = parser.parse_known_intermixed_args(argv)
4995 # unknown optionals go into extras
4996 self.assertEqual(NS(bar='y', cmd='cmd', foo='x', rest=[1]), args)
4997 self.assertEqual(['--error', '2', '3'], extras)
4998
4999 # restores attributes that were temporarily changed
5000 self.assertIsNone(parser.usage)
5001 self.assertEqual(bar.required, True)
5002
5003 def test_remainder(self):
5004 # Intermixed and remainder are incompatible
5005 parser = ErrorRaisingArgumentParser(prog='PROG')
5006 parser.add_argument('-z')
5007 parser.add_argument('x')
5008 parser.add_argument('y', nargs='...')
5009 argv = 'X A B -z Z'.split()
5010 # intermixed fails with '...' (also 'A...')
5011 # self.assertRaises(TypeError, parser.parse_intermixed_args, argv)
5012 with self.assertRaises(TypeError) as cm:
5013 parser.parse_intermixed_args(argv)
5014 self.assertRegex(str(cm.exception), r'\.\.\.')
5015
5016 def test_exclusive(self):
5017 # mutually exclusive group; intermixed works fine
5018 parser = ErrorRaisingArgumentParser(prog='PROG')
5019 group = parser.add_mutually_exclusive_group(required=True)
5020 group.add_argument('--foo', action='store_true', help='FOO')
5021 group.add_argument('--spam', help='SPAM')
5022 parser.add_argument('badger', nargs='*', default='X', help='BADGER')
5023 args = parser.parse_intermixed_args('1 --foo 2'.split())
5024 self.assertEqual(NS(badger=['1', '2'], foo=True, spam=None), args)
5025 self.assertRaises(ArgumentParserError, parser.parse_intermixed_args, '1 2'.split())
5026 self.assertEqual(group.required, True)
5027
5028 def test_exclusive_incompatible(self):
5029 # mutually exclusive group including positional - fail
5030 parser = ErrorRaisingArgumentParser(prog='PROG')
5031 group = parser.add_mutually_exclusive_group(required=True)
5032 group.add_argument('--foo', action='store_true', help='FOO')
5033 group.add_argument('--spam', help='SPAM')
5034 group.add_argument('badger', nargs='*', default='X', help='BADGER')
5035 self.assertRaises(TypeError, parser.parse_intermixed_args, [])
5036 self.assertEqual(group.required, True)
5037
5038class TestIntermixedMessageContentError(TestCase):
5039 # case where Intermixed gives different error message
5040 # error is raised by 1st parsing step
5041 def test_missing_argument_name_in_message(self):
5042 parser = ErrorRaisingArgumentParser(prog='PROG', usage='')
5043 parser.add_argument('req_pos', type=str)
5044 parser.add_argument('-req_opt', type=int, required=True)
5045
5046 with self.assertRaises(ArgumentParserError) as cm:
5047 parser.parse_args([])
5048 msg = str(cm.exception)
5049 self.assertRegex(msg, 'req_pos')
5050 self.assertRegex(msg, 'req_opt')
5051
5052 with self.assertRaises(ArgumentParserError) as cm:
5053 parser.parse_intermixed_args([])
5054 msg = str(cm.exception)
5055 self.assertNotRegex(msg, 'req_pos')
5056 self.assertRegex(msg, 'req_opt')
5057
Steven Bethard8d9a4622011-03-26 17:33:56 +01005058# ==========================
5059# add_argument metavar tests
5060# ==========================
5061
5062class TestAddArgumentMetavar(TestCase):
5063
5064 EXPECTED_MESSAGE = "length of metavar tuple does not match nargs"
5065
5066 def do_test_no_exception(self, nargs, metavar):
5067 parser = argparse.ArgumentParser()
5068 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
5069
5070 def do_test_exception(self, nargs, metavar):
5071 parser = argparse.ArgumentParser()
5072 with self.assertRaises(ValueError) as cm:
5073 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
5074 self.assertEqual(cm.exception.args[0], self.EXPECTED_MESSAGE)
5075
5076 # Unit tests for different values of metavar when nargs=None
5077
5078 def test_nargs_None_metavar_string(self):
5079 self.do_test_no_exception(nargs=None, metavar="1")
5080
5081 def test_nargs_None_metavar_length0(self):
5082 self.do_test_exception(nargs=None, metavar=tuple())
5083
5084 def test_nargs_None_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005085 self.do_test_no_exception(nargs=None, metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005086
5087 def test_nargs_None_metavar_length2(self):
5088 self.do_test_exception(nargs=None, metavar=("1", "2"))
5089
5090 def test_nargs_None_metavar_length3(self):
5091 self.do_test_exception(nargs=None, metavar=("1", "2", "3"))
5092
5093 # Unit tests for different values of metavar when nargs=?
5094
5095 def test_nargs_optional_metavar_string(self):
5096 self.do_test_no_exception(nargs="?", metavar="1")
5097
5098 def test_nargs_optional_metavar_length0(self):
5099 self.do_test_exception(nargs="?", metavar=tuple())
5100
5101 def test_nargs_optional_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005102 self.do_test_no_exception(nargs="?", metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005103
5104 def test_nargs_optional_metavar_length2(self):
5105 self.do_test_exception(nargs="?", metavar=("1", "2"))
5106
5107 def test_nargs_optional_metavar_length3(self):
5108 self.do_test_exception(nargs="?", metavar=("1", "2", "3"))
5109
5110 # Unit tests for different values of metavar when nargs=*
5111
5112 def test_nargs_zeroormore_metavar_string(self):
5113 self.do_test_no_exception(nargs="*", metavar="1")
5114
5115 def test_nargs_zeroormore_metavar_length0(self):
5116 self.do_test_exception(nargs="*", metavar=tuple())
5117
5118 def test_nargs_zeroormore_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005119 self.do_test_exception(nargs="*", metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005120
5121 def test_nargs_zeroormore_metavar_length2(self):
5122 self.do_test_no_exception(nargs="*", metavar=("1", "2"))
5123
5124 def test_nargs_zeroormore_metavar_length3(self):
5125 self.do_test_exception(nargs="*", metavar=("1", "2", "3"))
5126
5127 # Unit tests for different values of metavar when nargs=+
5128
5129 def test_nargs_oneormore_metavar_string(self):
5130 self.do_test_no_exception(nargs="+", metavar="1")
5131
5132 def test_nargs_oneormore_metavar_length0(self):
5133 self.do_test_exception(nargs="+", metavar=tuple())
5134
5135 def test_nargs_oneormore_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005136 self.do_test_exception(nargs="+", metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005137
5138 def test_nargs_oneormore_metavar_length2(self):
5139 self.do_test_no_exception(nargs="+", metavar=("1", "2"))
5140
5141 def test_nargs_oneormore_metavar_length3(self):
5142 self.do_test_exception(nargs="+", metavar=("1", "2", "3"))
5143
5144 # Unit tests for different values of metavar when nargs=...
5145
5146 def test_nargs_remainder_metavar_string(self):
5147 self.do_test_no_exception(nargs="...", metavar="1")
5148
5149 def test_nargs_remainder_metavar_length0(self):
5150 self.do_test_no_exception(nargs="...", metavar=tuple())
5151
5152 def test_nargs_remainder_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005153 self.do_test_no_exception(nargs="...", metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005154
5155 def test_nargs_remainder_metavar_length2(self):
5156 self.do_test_no_exception(nargs="...", metavar=("1", "2"))
5157
5158 def test_nargs_remainder_metavar_length3(self):
5159 self.do_test_no_exception(nargs="...", metavar=("1", "2", "3"))
5160
5161 # Unit tests for different values of metavar when nargs=A...
5162
5163 def test_nargs_parser_metavar_string(self):
5164 self.do_test_no_exception(nargs="A...", metavar="1")
5165
5166 def test_nargs_parser_metavar_length0(self):
5167 self.do_test_exception(nargs="A...", metavar=tuple())
5168
5169 def test_nargs_parser_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005170 self.do_test_no_exception(nargs="A...", metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005171
5172 def test_nargs_parser_metavar_length2(self):
5173 self.do_test_exception(nargs="A...", metavar=("1", "2"))
5174
5175 def test_nargs_parser_metavar_length3(self):
5176 self.do_test_exception(nargs="A...", metavar=("1", "2", "3"))
5177
5178 # Unit tests for different values of metavar when nargs=1
5179
5180 def test_nargs_1_metavar_string(self):
5181 self.do_test_no_exception(nargs=1, metavar="1")
5182
5183 def test_nargs_1_metavar_length0(self):
5184 self.do_test_exception(nargs=1, metavar=tuple())
5185
5186 def test_nargs_1_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005187 self.do_test_no_exception(nargs=1, metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005188
5189 def test_nargs_1_metavar_length2(self):
5190 self.do_test_exception(nargs=1, metavar=("1", "2"))
5191
5192 def test_nargs_1_metavar_length3(self):
5193 self.do_test_exception(nargs=1, metavar=("1", "2", "3"))
5194
5195 # Unit tests for different values of metavar when nargs=2
5196
5197 def test_nargs_2_metavar_string(self):
5198 self.do_test_no_exception(nargs=2, metavar="1")
5199
5200 def test_nargs_2_metavar_length0(self):
5201 self.do_test_exception(nargs=2, metavar=tuple())
5202
5203 def test_nargs_2_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005204 self.do_test_exception(nargs=2, metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005205
5206 def test_nargs_2_metavar_length2(self):
5207 self.do_test_no_exception(nargs=2, metavar=("1", "2"))
5208
5209 def test_nargs_2_metavar_length3(self):
5210 self.do_test_exception(nargs=2, metavar=("1", "2", "3"))
5211
5212 # Unit tests for different values of metavar when nargs=3
5213
5214 def test_nargs_3_metavar_string(self):
5215 self.do_test_no_exception(nargs=3, metavar="1")
5216
5217 def test_nargs_3_metavar_length0(self):
5218 self.do_test_exception(nargs=3, metavar=tuple())
5219
5220 def test_nargs_3_metavar_length1(self):
wim glenn66f02aa2018-06-08 05:12:49 -05005221 self.do_test_exception(nargs=3, metavar=("1",))
Steven Bethard8d9a4622011-03-26 17:33:56 +01005222
5223 def test_nargs_3_metavar_length2(self):
5224 self.do_test_exception(nargs=3, metavar=("1", "2"))
5225
5226 def test_nargs_3_metavar_length3(self):
5227 self.do_test_no_exception(nargs=3, metavar=("1", "2", "3"))
5228
Miss Islington (bot)1cc70322019-08-01 22:16:44 -07005229
5230class TestInvalidNargs(TestCase):
5231
5232 EXPECTED_INVALID_MESSAGE = "invalid nargs value"
5233 EXPECTED_RANGE_MESSAGE = ("nargs for store actions must be != 0; if you "
5234 "have nothing to store, actions such as store "
5235 "true or store const may be more appropriate")
5236
5237 def do_test_range_exception(self, nargs):
5238 parser = argparse.ArgumentParser()
5239 with self.assertRaises(ValueError) as cm:
5240 parser.add_argument("--foo", nargs=nargs)
5241 self.assertEqual(cm.exception.args[0], self.EXPECTED_RANGE_MESSAGE)
5242
5243 def do_test_invalid_exception(self, nargs):
5244 parser = argparse.ArgumentParser()
5245 with self.assertRaises(ValueError) as cm:
5246 parser.add_argument("--foo", nargs=nargs)
5247 self.assertEqual(cm.exception.args[0], self.EXPECTED_INVALID_MESSAGE)
5248
5249 # Unit tests for different values of nargs
5250
5251 def test_nargs_alphabetic(self):
5252 self.do_test_invalid_exception(nargs='a')
5253 self.do_test_invalid_exception(nargs="abcd")
5254
5255 def test_nargs_zero(self):
5256 self.do_test_range_exception(nargs=0)
5257
Benjamin Peterson698a18a2010-03-02 22:34:37 +00005258# ============================
5259# from argparse import * tests
5260# ============================
5261
5262class TestImportStar(TestCase):
5263
5264 def test(self):
5265 for name in argparse.__all__:
5266 self.assertTrue(hasattr(argparse, name))
5267
Steven Bethard72c55382010-11-01 15:23:12 +00005268 def test_all_exports_everything_but_modules(self):
5269 items = [
5270 name
5271 for name, value in vars(argparse).items()
Éric Araujo12159152010-12-04 17:31:49 +00005272 if not (name.startswith("_") or name == 'ngettext')
Steven Bethard72c55382010-11-01 15:23:12 +00005273 if not inspect.ismodule(value)
5274 ]
5275 self.assertEqual(sorted(items), sorted(argparse.__all__))
5276
wim glenn66f02aa2018-06-08 05:12:49 -05005277
5278class TestWrappingMetavar(TestCase):
5279
5280 def setUp(self):
Berker Peksag74102c92018-07-25 18:23:44 +03005281 super().setUp()
wim glenn66f02aa2018-06-08 05:12:49 -05005282 self.parser = ErrorRaisingArgumentParser(
5283 'this_is_spammy_prog_with_a_long_name_sorry_about_the_name'
5284 )
5285 # this metavar was triggering library assertion errors due to usage
5286 # message formatting incorrectly splitting on the ] chars within
5287 metavar = '<http[s]://example:1234>'
5288 self.parser.add_argument('--proxy', metavar=metavar)
5289
5290 def test_help_with_metavar(self):
5291 help_text = self.parser.format_help()
5292 self.assertEqual(help_text, textwrap.dedent('''\
5293 usage: this_is_spammy_prog_with_a_long_name_sorry_about_the_name
5294 [-h] [--proxy <http[s]://example:1234>]
5295
5296 optional arguments:
5297 -h, --help show this help message and exit
5298 --proxy <http[s]://example:1234>
5299 '''))
5300
5301
Benjamin Peterson698a18a2010-03-02 22:34:37 +00005302def test_main():
Florent Xiclunaaf1adbe2012-07-07 17:02:22 +02005303 support.run_unittest(__name__)
Benjamin Peterson4fd181c2010-03-02 23:46:42 +00005304 # Remove global references to avoid looking like we have refleaks.
5305 RFile.seen = {}
5306 WFile.seen = set()
5307
Benjamin Peterson698a18a2010-03-02 22:34:37 +00005308
5309
5310if __name__ == '__main__':
5311 test_main()