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