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