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