blob: 99c1babb4acee3b47490064b5b34458a71f6edea [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
2939
2940class TestHelpBiggerOptionalGroups(HelpTestCase):
2941 """Make sure that argument help aligns when options are longer"""
2942
2943 parser_signature = Sig(prog='PROG', description='DESCRIPTION',
2944 epilog='EPILOG', version='0.1')
2945 argument_signatures = [
2946 Sig('-x', action='store_true', help='X HELP'),
2947 Sig('--y', help='Y HELP'),
2948 Sig('foo', help='FOO HELP'),
2949 Sig('bar', help='BAR HELP'),
2950 ]
2951 argument_group_signatures = [
2952 (Sig('GROUP TITLE', description='GROUP DESCRIPTION'), [
2953 Sig('baz', help='BAZ HELP'),
2954 Sig('-z', nargs='+', help='Z HELP')]),
2955 ]
2956 usage = '''\
2957 usage: PROG [-h] [-v] [-x] [--y Y] [-z Z [Z ...]] foo bar baz
2958 '''
2959 help = usage + '''\
2960
2961 DESCRIPTION
2962
2963 positional arguments:
2964 foo FOO HELP
2965 bar BAR HELP
2966
2967 optional arguments:
2968 -h, --help show this help message and exit
2969 -v, --version show program's version number and exit
2970 -x X HELP
2971 --y Y Y HELP
2972
2973 GROUP TITLE:
2974 GROUP DESCRIPTION
2975
2976 baz BAZ HELP
2977 -z Z [Z ...] Z HELP
2978
2979 EPILOG
2980 '''
2981 version = '''\
2982 0.1
2983 '''
2984
2985
2986class TestHelpBiggerPositionals(HelpTestCase):
2987 """Make sure that help aligns when arguments are longer"""
2988
2989 parser_signature = Sig(usage='USAGE', description='DESCRIPTION')
2990 argument_signatures = [
2991 Sig('-x', action='store_true', help='X HELP'),
2992 Sig('--y', help='Y HELP'),
2993 Sig('ekiekiekifekang', help='EKI HELP'),
2994 Sig('bar', help='BAR HELP'),
2995 ]
2996 argument_group_signatures = []
2997 usage = '''\
2998 usage: USAGE
2999 '''
3000 help = usage + '''\
3001
3002 DESCRIPTION
3003
3004 positional arguments:
3005 ekiekiekifekang EKI HELP
3006 bar BAR HELP
3007
3008 optional arguments:
3009 -h, --help show this help message and exit
3010 -x X HELP
3011 --y Y Y HELP
3012 '''
3013
3014 version = ''
3015
3016
3017class TestHelpReformatting(HelpTestCase):
3018 """Make sure that text after short names starts on the first line"""
3019
3020 parser_signature = Sig(
3021 prog='PROG',
3022 description=' oddly formatted\n'
3023 'description\n'
3024 '\n'
3025 'that is so long that it should go onto multiple '
3026 'lines when wrapped')
3027 argument_signatures = [
3028 Sig('-x', metavar='XX', help='oddly\n'
3029 ' formatted -x help'),
3030 Sig('y', metavar='yyy', help='normal y help'),
3031 ]
3032 argument_group_signatures = [
3033 (Sig('title', description='\n'
3034 ' oddly formatted group\n'
3035 '\n'
3036 'description'),
3037 [Sig('-a', action='store_true',
3038 help=' oddly \n'
3039 'formatted -a help \n'
3040 ' again, so long that it should be wrapped over '
3041 'multiple lines')]),
3042 ]
3043 usage = '''\
3044 usage: PROG [-h] [-x XX] [-a] yyy
3045 '''
3046 help = usage + '''\
3047
3048 oddly formatted description that is so long that it should go onto \
3049multiple
3050 lines when wrapped
3051
3052 positional arguments:
3053 yyy normal y help
3054
3055 optional arguments:
3056 -h, --help show this help message and exit
3057 -x XX oddly formatted -x help
3058
3059 title:
3060 oddly formatted group description
3061
3062 -a oddly formatted -a help again, so long that it should \
3063be wrapped
3064 over multiple lines
3065 '''
3066 version = ''
3067
3068
3069class TestHelpWrappingShortNames(HelpTestCase):
3070 """Make sure that text after short names starts on the first line"""
3071
3072 parser_signature = Sig(prog='PROG', description= 'D\nD' * 30)
3073 argument_signatures = [
3074 Sig('-x', metavar='XX', help='XHH HX' * 20),
3075 Sig('y', metavar='yyy', help='YH YH' * 20),
3076 ]
3077 argument_group_signatures = [
3078 (Sig('ALPHAS'), [
3079 Sig('-a', action='store_true', help='AHHH HHA' * 10)]),
3080 ]
3081 usage = '''\
3082 usage: PROG [-h] [-x XX] [-a] yyy
3083 '''
3084 help = usage + '''\
3085
3086 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3087DD DD DD
3088 DD DD DD DD D
3089
3090 positional arguments:
3091 yyy YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3092YHYH YHYH
3093 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3094
3095 optional arguments:
3096 -h, --help show this help message and exit
3097 -x XX XHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH \
3098HXXHH HXXHH
3099 HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HXXHH HX
3100
3101 ALPHAS:
3102 -a AHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH HHAAHHH \
3103HHAAHHH
3104 HHAAHHH HHAAHHH HHA
3105 '''
3106 version = ''
3107
3108
3109class TestHelpWrappingLongNames(HelpTestCase):
3110 """Make sure that text after long names starts on the next line"""
3111
3112 parser_signature = Sig(usage='USAGE', description= 'D D' * 30,
3113 version='V V'*30)
3114 argument_signatures = [
3115 Sig('-x', metavar='X' * 25, help='XH XH' * 20),
3116 Sig('y', metavar='y' * 25, help='YH YH' * 20),
3117 ]
3118 argument_group_signatures = [
3119 (Sig('ALPHAS'), [
3120 Sig('-a', metavar='A' * 25, help='AH AH' * 20),
3121 Sig('z', metavar='z' * 25, help='ZH ZH' * 20)]),
3122 ]
3123 usage = '''\
3124 usage: USAGE
3125 '''
3126 help = usage + '''\
3127
3128 D DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD DD \
3129DD DD DD
3130 DD DD DD DD D
3131
3132 positional arguments:
3133 yyyyyyyyyyyyyyyyyyyyyyyyy
3134 YH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH \
3135YHYH YHYH
3136 YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YHYH YH
3137
3138 optional arguments:
3139 -h, --help show this help message and exit
3140 -v, --version show program's version number and exit
3141 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3142 XH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH \
3143XHXH XHXH
3144 XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XHXH XH
3145
3146 ALPHAS:
3147 -a AAAAAAAAAAAAAAAAAAAAAAAAA
3148 AH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH \
3149AHAH AHAH
3150 AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AHAH AH
3151 zzzzzzzzzzzzzzzzzzzzzzzzz
3152 ZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH \
3153ZHZH ZHZH
3154 ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZHZH ZH
3155 '''
3156 version = '''\
3157 V VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV VV \
3158VV VV VV
3159 VV VV VV VV V
3160 '''
3161
3162
3163class TestHelpUsage(HelpTestCase):
3164 """Test basic usage messages"""
3165
3166 parser_signature = Sig(prog='PROG')
3167 argument_signatures = [
3168 Sig('-w', nargs='+', help='w'),
3169 Sig('-x', nargs='*', help='x'),
3170 Sig('a', help='a'),
3171 Sig('b', help='b', nargs=2),
3172 Sig('c', help='c', nargs='?'),
3173 ]
3174 argument_group_signatures = [
3175 (Sig('group'), [
3176 Sig('-y', nargs='?', help='y'),
3177 Sig('-z', nargs=3, help='z'),
3178 Sig('d', help='d', nargs='*'),
3179 Sig('e', help='e', nargs='+'),
3180 ])
3181 ]
3182 usage = '''\
3183 usage: PROG [-h] [-w W [W ...]] [-x [X [X ...]]] [-y [Y]] [-z Z Z Z]
3184 a b b [c] [d [d ...]] e [e ...]
3185 '''
3186 help = usage + '''\
3187
3188 positional arguments:
3189 a a
3190 b b
3191 c c
3192
3193 optional arguments:
3194 -h, --help show this help message and exit
3195 -w W [W ...] w
3196 -x [X [X ...]] x
3197
3198 group:
3199 -y [Y] y
3200 -z Z Z Z z
3201 d d
3202 e e
3203 '''
3204 version = ''
3205
3206
3207class TestHelpOnlyUserGroups(HelpTestCase):
3208 """Test basic usage messages"""
3209
3210 parser_signature = Sig(prog='PROG', add_help=False)
3211 argument_signatures = []
3212 argument_group_signatures = [
3213 (Sig('xxxx'), [
3214 Sig('-x', help='x'),
3215 Sig('a', help='a'),
3216 ]),
3217 (Sig('yyyy'), [
3218 Sig('b', help='b'),
3219 Sig('-y', help='y'),
3220 ]),
3221 ]
3222 usage = '''\
3223 usage: PROG [-x X] [-y Y] a b
3224 '''
3225 help = usage + '''\
3226
3227 xxxx:
3228 -x X x
3229 a a
3230
3231 yyyy:
3232 b b
3233 -y Y y
3234 '''
3235 version = ''
3236
3237
3238class TestHelpUsageLongProg(HelpTestCase):
3239 """Test usage messages where the prog is long"""
3240
3241 parser_signature = Sig(prog='P' * 60)
3242 argument_signatures = [
3243 Sig('-w', metavar='W'),
3244 Sig('-x', metavar='X'),
3245 Sig('a'),
3246 Sig('b'),
3247 ]
3248 argument_group_signatures = []
3249 usage = '''\
3250 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3251 [-h] [-w W] [-x X] a b
3252 '''
3253 help = usage + '''\
3254
3255 positional arguments:
3256 a
3257 b
3258
3259 optional arguments:
3260 -h, --help show this help message and exit
3261 -w W
3262 -x X
3263 '''
3264 version = ''
3265
3266
3267class TestHelpUsageLongProgOptionsWrap(HelpTestCase):
3268 """Test usage messages where the prog is long and the optionals wrap"""
3269
3270 parser_signature = Sig(prog='P' * 60)
3271 argument_signatures = [
3272 Sig('-w', metavar='W' * 25),
3273 Sig('-x', metavar='X' * 25),
3274 Sig('-y', metavar='Y' * 25),
3275 Sig('-z', metavar='Z' * 25),
3276 Sig('a'),
3277 Sig('b'),
3278 ]
3279 argument_group_signatures = []
3280 usage = '''\
3281 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3282 [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3283[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3284 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3285 a b
3286 '''
3287 help = usage + '''\
3288
3289 positional arguments:
3290 a
3291 b
3292
3293 optional arguments:
3294 -h, --help show this help message and exit
3295 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3296 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3297 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3298 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3299 '''
3300 version = ''
3301
3302
3303class TestHelpUsageLongProgPositionalsWrap(HelpTestCase):
3304 """Test usage messages where the prog is long and the positionals wrap"""
3305
3306 parser_signature = Sig(prog='P' * 60, add_help=False)
3307 argument_signatures = [
3308 Sig('a' * 25),
3309 Sig('b' * 25),
3310 Sig('c' * 25),
3311 ]
3312 argument_group_signatures = []
3313 usage = '''\
3314 usage: PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP
3315 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3316 ccccccccccccccccccccccccc
3317 '''
3318 help = usage + '''\
3319
3320 positional arguments:
3321 aaaaaaaaaaaaaaaaaaaaaaaaa
3322 bbbbbbbbbbbbbbbbbbbbbbbbb
3323 ccccccccccccccccccccccccc
3324 '''
3325 version = ''
3326
3327
3328class TestHelpUsageOptionalsWrap(HelpTestCase):
3329 """Test usage messages where the optionals wrap"""
3330
3331 parser_signature = Sig(prog='PROG')
3332 argument_signatures = [
3333 Sig('-w', metavar='W' * 25),
3334 Sig('-x', metavar='X' * 25),
3335 Sig('-y', metavar='Y' * 25),
3336 Sig('-z', metavar='Z' * 25),
3337 Sig('a'),
3338 Sig('b'),
3339 Sig('c'),
3340 ]
3341 argument_group_signatures = []
3342 usage = '''\
3343 usage: PROG [-h] [-w WWWWWWWWWWWWWWWWWWWWWWWWW] \
3344[-x XXXXXXXXXXXXXXXXXXXXXXXXX]
3345 [-y YYYYYYYYYYYYYYYYYYYYYYYYY] \
3346[-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3347 a b c
3348 '''
3349 help = usage + '''\
3350
3351 positional arguments:
3352 a
3353 b
3354 c
3355
3356 optional arguments:
3357 -h, --help show this help message and exit
3358 -w WWWWWWWWWWWWWWWWWWWWWWWWW
3359 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3360 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3361 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3362 '''
3363 version = ''
3364
3365
3366class TestHelpUsagePositionalsWrap(HelpTestCase):
3367 """Test usage messages where the positionals wrap"""
3368
3369 parser_signature = Sig(prog='PROG')
3370 argument_signatures = [
3371 Sig('-x'),
3372 Sig('-y'),
3373 Sig('-z'),
3374 Sig('a' * 25),
3375 Sig('b' * 25),
3376 Sig('c' * 25),
3377 ]
3378 argument_group_signatures = []
3379 usage = '''\
3380 usage: PROG [-h] [-x X] [-y Y] [-z Z]
3381 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3382 ccccccccccccccccccccccccc
3383 '''
3384 help = usage + '''\
3385
3386 positional arguments:
3387 aaaaaaaaaaaaaaaaaaaaaaaaa
3388 bbbbbbbbbbbbbbbbbbbbbbbbb
3389 ccccccccccccccccccccccccc
3390
3391 optional arguments:
3392 -h, --help show this help message and exit
3393 -x X
3394 -y Y
3395 -z Z
3396 '''
3397 version = ''
3398
3399
3400class TestHelpUsageOptionalsPositionalsWrap(HelpTestCase):
3401 """Test usage messages where the optionals and positionals wrap"""
3402
3403 parser_signature = Sig(prog='PROG')
3404 argument_signatures = [
3405 Sig('-x', metavar='X' * 25),
3406 Sig('-y', metavar='Y' * 25),
3407 Sig('-z', metavar='Z' * 25),
3408 Sig('a' * 25),
3409 Sig('b' * 25),
3410 Sig('c' * 25),
3411 ]
3412 argument_group_signatures = []
3413 usage = '''\
3414 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3415[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3416 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3417 aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3418 ccccccccccccccccccccccccc
3419 '''
3420 help = usage + '''\
3421
3422 positional arguments:
3423 aaaaaaaaaaaaaaaaaaaaaaaaa
3424 bbbbbbbbbbbbbbbbbbbbbbbbb
3425 ccccccccccccccccccccccccc
3426
3427 optional arguments:
3428 -h, --help show this help message and exit
3429 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3430 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3431 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3432 '''
3433 version = ''
3434
3435
3436class TestHelpUsageOptionalsOnlyWrap(HelpTestCase):
3437 """Test usage messages where there are only optionals and they wrap"""
3438
3439 parser_signature = Sig(prog='PROG')
3440 argument_signatures = [
3441 Sig('-x', metavar='X' * 25),
3442 Sig('-y', metavar='Y' * 25),
3443 Sig('-z', metavar='Z' * 25),
3444 ]
3445 argument_group_signatures = []
3446 usage = '''\
3447 usage: PROG [-h] [-x XXXXXXXXXXXXXXXXXXXXXXXXX] \
3448[-y YYYYYYYYYYYYYYYYYYYYYYYYY]
3449 [-z ZZZZZZZZZZZZZZZZZZZZZZZZZ]
3450 '''
3451 help = usage + '''\
3452
3453 optional arguments:
3454 -h, --help show this help message and exit
3455 -x XXXXXXXXXXXXXXXXXXXXXXXXX
3456 -y YYYYYYYYYYYYYYYYYYYYYYYYY
3457 -z ZZZZZZZZZZZZZZZZZZZZZZZZZ
3458 '''
3459 version = ''
3460
3461
3462class TestHelpUsagePositionalsOnlyWrap(HelpTestCase):
3463 """Test usage messages where there are only positionals and they wrap"""
3464
3465 parser_signature = Sig(prog='PROG', add_help=False)
3466 argument_signatures = [
3467 Sig('a' * 25),
3468 Sig('b' * 25),
3469 Sig('c' * 25),
3470 ]
3471 argument_group_signatures = []
3472 usage = '''\
3473 usage: PROG aaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbb
3474 ccccccccccccccccccccccccc
3475 '''
3476 help = usage + '''\
3477
3478 positional arguments:
3479 aaaaaaaaaaaaaaaaaaaaaaaaa
3480 bbbbbbbbbbbbbbbbbbbbbbbbb
3481 ccccccccccccccccccccccccc
3482 '''
3483 version = ''
3484
3485
3486class TestHelpVariableExpansion(HelpTestCase):
3487 """Test that variables are expanded properly in help messages"""
3488
3489 parser_signature = Sig(prog='PROG')
3490 argument_signatures = [
3491 Sig('-x', type=int,
3492 help='x %(prog)s %(default)s %(type)s %%'),
3493 Sig('-y', action='store_const', default=42, const='XXX',
3494 help='y %(prog)s %(default)s %(const)s'),
3495 Sig('--foo', choices='abc',
3496 help='foo %(prog)s %(default)s %(choices)s'),
3497 Sig('--bar', default='baz', choices=[1, 2], metavar='BBB',
3498 help='bar %(prog)s %(default)s %(dest)s'),
3499 Sig('spam', help='spam %(prog)s %(default)s'),
3500 Sig('badger', default=0.5, help='badger %(prog)s %(default)s'),
3501 ]
3502 argument_group_signatures = [
3503 (Sig('group'), [
3504 Sig('-a', help='a %(prog)s %(default)s'),
3505 Sig('-b', default=-1, help='b %(prog)s %(default)s'),
3506 ])
3507 ]
3508 usage = ('''\
3509 usage: PROG [-h] [-x X] [-y] [--foo {a,b,c}] [--bar BBB] [-a A] [-b B]
3510 spam badger
3511 ''')
3512 help = usage + '''\
3513
3514 positional arguments:
3515 spam spam PROG None
3516 badger badger PROG 0.5
3517
3518 optional arguments:
3519 -h, --help show this help message and exit
3520 -x X x PROG None int %
3521 -y y PROG 42 XXX
3522 --foo {a,b,c} foo PROG None a, b, c
3523 --bar BBB bar PROG baz bar
3524
3525 group:
3526 -a A a PROG None
3527 -b B b PROG -1
3528 '''
3529 version = ''
3530
3531
3532class TestHelpVariableExpansionUsageSupplied(HelpTestCase):
3533 """Test that variables are expanded properly when usage= is present"""
3534
3535 parser_signature = Sig(prog='PROG', usage='%(prog)s FOO')
3536 argument_signatures = []
3537 argument_group_signatures = []
3538 usage = ('''\
3539 usage: PROG FOO
3540 ''')
3541 help = usage + '''\
3542
3543 optional arguments:
3544 -h, --help show this help message and exit
3545 '''
3546 version = ''
3547
3548
3549class TestHelpVariableExpansionNoArguments(HelpTestCase):
3550 """Test that variables are expanded properly with no arguments"""
3551
3552 parser_signature = Sig(prog='PROG', add_help=False)
3553 argument_signatures = []
3554 argument_group_signatures = []
3555 usage = ('''\
3556 usage: PROG
3557 ''')
3558 help = usage
3559 version = ''
3560
3561
3562class TestHelpSuppressUsage(HelpTestCase):
3563 """Test that items can be suppressed in usage messages"""
3564
3565 parser_signature = Sig(prog='PROG', usage=argparse.SUPPRESS)
3566 argument_signatures = [
3567 Sig('--foo', help='foo help'),
3568 Sig('spam', help='spam help'),
3569 ]
3570 argument_group_signatures = []
3571 help = '''\
3572 positional arguments:
3573 spam spam help
3574
3575 optional arguments:
3576 -h, --help show this help message and exit
3577 --foo FOO foo help
3578 '''
3579 usage = ''
3580 version = ''
3581
3582
3583class TestHelpSuppressOptional(HelpTestCase):
3584 """Test that optional arguments can be suppressed in help messages"""
3585
3586 parser_signature = Sig(prog='PROG', add_help=False)
3587 argument_signatures = [
3588 Sig('--foo', help=argparse.SUPPRESS),
3589 Sig('spam', help='spam help'),
3590 ]
3591 argument_group_signatures = []
3592 usage = '''\
3593 usage: PROG spam
3594 '''
3595 help = usage + '''\
3596
3597 positional arguments:
3598 spam spam help
3599 '''
3600 version = ''
3601
3602
3603class TestHelpSuppressOptionalGroup(HelpTestCase):
3604 """Test that optional groups can be suppressed in help messages"""
3605
3606 parser_signature = Sig(prog='PROG')
3607 argument_signatures = [
3608 Sig('--foo', help='foo help'),
3609 Sig('spam', help='spam help'),
3610 ]
3611 argument_group_signatures = [
3612 (Sig('group'), [Sig('--bar', help=argparse.SUPPRESS)]),
3613 ]
3614 usage = '''\
3615 usage: PROG [-h] [--foo FOO] spam
3616 '''
3617 help = usage + '''\
3618
3619 positional arguments:
3620 spam spam help
3621
3622 optional arguments:
3623 -h, --help show this help message and exit
3624 --foo FOO foo help
3625 '''
3626 version = ''
3627
3628
3629class TestHelpSuppressPositional(HelpTestCase):
3630 """Test that positional arguments can be suppressed in help messages"""
3631
3632 parser_signature = Sig(prog='PROG')
3633 argument_signatures = [
3634 Sig('--foo', help='foo help'),
3635 Sig('spam', help=argparse.SUPPRESS),
3636 ]
3637 argument_group_signatures = []
3638 usage = '''\
3639 usage: PROG [-h] [--foo FOO]
3640 '''
3641 help = usage + '''\
3642
3643 optional arguments:
3644 -h, --help show this help message and exit
3645 --foo FOO foo help
3646 '''
3647 version = ''
3648
3649
3650class TestHelpRequiredOptional(HelpTestCase):
3651 """Test that required options don't look optional"""
3652
3653 parser_signature = Sig(prog='PROG')
3654 argument_signatures = [
3655 Sig('--foo', required=True, help='foo help'),
3656 ]
3657 argument_group_signatures = []
3658 usage = '''\
3659 usage: PROG [-h] --foo FOO
3660 '''
3661 help = usage + '''\
3662
3663 optional arguments:
3664 -h, --help show this help message and exit
3665 --foo FOO foo help
3666 '''
3667 version = ''
3668
3669
3670class TestHelpAlternatePrefixChars(HelpTestCase):
3671 """Test that options display with different prefix characters"""
3672
3673 parser_signature = Sig(prog='PROG', prefix_chars='^;', add_help=False)
3674 argument_signatures = [
3675 Sig('^^foo', action='store_true', help='foo help'),
3676 Sig(';b', ';;bar', help='bar help'),
3677 ]
3678 argument_group_signatures = []
3679 usage = '''\
3680 usage: PROG [^^foo] [;b BAR]
3681 '''
3682 help = usage + '''\
3683
3684 optional arguments:
3685 ^^foo foo help
3686 ;b BAR, ;;bar BAR bar help
3687 '''
3688 version = ''
3689
3690
3691class TestHelpNoHelpOptional(HelpTestCase):
3692 """Test that the --help argument can be suppressed help messages"""
3693
3694 parser_signature = Sig(prog='PROG', add_help=False)
3695 argument_signatures = [
3696 Sig('--foo', help='foo help'),
3697 Sig('spam', help='spam help'),
3698 ]
3699 argument_group_signatures = []
3700 usage = '''\
3701 usage: PROG [--foo FOO] spam
3702 '''
3703 help = usage + '''\
3704
3705 positional arguments:
3706 spam spam help
3707
3708 optional arguments:
3709 --foo FOO foo help
3710 '''
3711 version = ''
3712
3713
3714class TestHelpVersionOptional(HelpTestCase):
3715 """Test that the --version argument can be suppressed help messages"""
3716
3717 parser_signature = Sig(prog='PROG', version='1.0')
3718 argument_signatures = [
3719 Sig('--foo', help='foo help'),
3720 Sig('spam', help='spam help'),
3721 ]
3722 argument_group_signatures = []
3723 usage = '''\
3724 usage: PROG [-h] [-v] [--foo FOO] spam
3725 '''
3726 help = usage + '''\
3727
3728 positional arguments:
3729 spam spam help
3730
3731 optional arguments:
3732 -h, --help show this help message and exit
3733 -v, --version show program's version number and exit
3734 --foo FOO foo help
3735 '''
3736 version = '''\
3737 1.0
3738 '''
3739
3740
3741class TestHelpNone(HelpTestCase):
3742 """Test that no errors occur if no help is specified"""
3743
3744 parser_signature = Sig(prog='PROG')
3745 argument_signatures = [
3746 Sig('--foo'),
3747 Sig('spam'),
3748 ]
3749 argument_group_signatures = []
3750 usage = '''\
3751 usage: PROG [-h] [--foo FOO] spam
3752 '''
3753 help = usage + '''\
3754
3755 positional arguments:
3756 spam
3757
3758 optional arguments:
3759 -h, --help show this help message and exit
3760 --foo FOO
3761 '''
3762 version = ''
3763
3764
3765class TestHelpTupleMetavar(HelpTestCase):
3766 """Test specifying metavar as a tuple"""
3767
3768 parser_signature = Sig(prog='PROG')
3769 argument_signatures = [
3770 Sig('-w', help='w', nargs='+', metavar=('W1', 'W2')),
3771 Sig('-x', help='x', nargs='*', metavar=('X1', 'X2')),
3772 Sig('-y', help='y', nargs=3, metavar=('Y1', 'Y2', 'Y3')),
3773 Sig('-z', help='z', nargs='?', metavar=('Z1', )),
3774 ]
3775 argument_group_signatures = []
3776 usage = '''\
3777 usage: PROG [-h] [-w W1 [W2 ...]] [-x [X1 [X2 ...]]] [-y Y1 Y2 Y3] \
3778[-z [Z1]]
3779 '''
3780 help = usage + '''\
3781
3782 optional arguments:
3783 -h, --help show this help message and exit
3784 -w W1 [W2 ...] w
3785 -x [X1 [X2 ...]] x
3786 -y Y1 Y2 Y3 y
3787 -z [Z1] z
3788 '''
3789 version = ''
3790
3791
3792class TestHelpRawText(HelpTestCase):
3793 """Test the RawTextHelpFormatter"""
3794
3795 parser_signature = Sig(
3796 prog='PROG', formatter_class=argparse.RawTextHelpFormatter,
3797 description='Keep the formatting\n'
3798 ' exactly as it is written\n'
3799 '\n'
3800 'here\n')
3801
3802 argument_signatures = [
3803 Sig('--foo', help=' foo help should also\n'
3804 'appear as given here'),
3805 Sig('spam', help='spam help'),
3806 ]
3807 argument_group_signatures = [
3808 (Sig('title', description=' This text\n'
3809 ' should be indented\n'
3810 ' exactly like it is here\n'),
3811 [Sig('--bar', help='bar help')]),
3812 ]
3813 usage = '''\
3814 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3815 '''
3816 help = usage + '''\
3817
3818 Keep the formatting
3819 exactly as it is written
3820
3821 here
3822
3823 positional arguments:
3824 spam spam help
3825
3826 optional arguments:
3827 -h, --help show this help message and exit
3828 --foo FOO foo help should also
3829 appear as given here
3830
3831 title:
3832 This text
3833 should be indented
3834 exactly like it is here
3835
3836 --bar BAR bar help
3837 '''
3838 version = ''
3839
3840
3841class TestHelpRawDescription(HelpTestCase):
3842 """Test the RawTextHelpFormatter"""
3843
3844 parser_signature = Sig(
3845 prog='PROG', formatter_class=argparse.RawDescriptionHelpFormatter,
3846 description='Keep the formatting\n'
3847 ' exactly as it is written\n'
3848 '\n'
3849 'here\n')
3850
3851 argument_signatures = [
3852 Sig('--foo', help=' foo help should not\n'
3853 ' retain this odd formatting'),
3854 Sig('spam', help='spam help'),
3855 ]
3856 argument_group_signatures = [
3857 (Sig('title', description=' This text\n'
3858 ' should be indented\n'
3859 ' exactly like it is here\n'),
3860 [Sig('--bar', help='bar help')]),
3861 ]
3862 usage = '''\
3863 usage: PROG [-h] [--foo FOO] [--bar BAR] spam
3864 '''
3865 help = usage + '''\
3866
3867 Keep the formatting
3868 exactly as it is written
3869
3870 here
3871
3872 positional arguments:
3873 spam spam help
3874
3875 optional arguments:
3876 -h, --help show this help message and exit
3877 --foo FOO foo help should not retain this odd formatting
3878
3879 title:
3880 This text
3881 should be indented
3882 exactly like it is here
3883
3884 --bar BAR bar help
3885 '''
3886 version = ''
3887
3888
3889class TestHelpArgumentDefaults(HelpTestCase):
3890 """Test the ArgumentDefaultsHelpFormatter"""
3891
3892 parser_signature = Sig(
3893 prog='PROG', formatter_class=argparse.ArgumentDefaultsHelpFormatter,
3894 description='description')
3895
3896 argument_signatures = [
3897 Sig('--foo', help='foo help - oh and by the way, %(default)s'),
3898 Sig('--bar', action='store_true', help='bar help'),
3899 Sig('spam', help='spam help'),
3900 Sig('badger', nargs='?', default='wooden', help='badger help'),
3901 ]
3902 argument_group_signatures = [
3903 (Sig('title', description='description'),
3904 [Sig('--baz', type=int, default=42, help='baz help')]),
3905 ]
3906 usage = '''\
3907 usage: PROG [-h] [--foo FOO] [--bar] [--baz BAZ] spam [badger]
3908 '''
3909 help = usage + '''\
3910
3911 description
3912
3913 positional arguments:
3914 spam spam help
3915 badger badger help (default: wooden)
3916
3917 optional arguments:
3918 -h, --help show this help message and exit
3919 --foo FOO foo help - oh and by the way, None
3920 --bar bar help (default: False)
3921
3922 title:
3923 description
3924
3925 --baz BAZ baz help (default: 42)
3926 '''
3927 version = ''
3928
Steven Betharddce6e1b2010-05-24 03:45:26 +00003929class TestHelpVersionAction(HelpTestCase):
3930 """Test the default help for the version action"""
3931
3932 parser_signature = Sig(prog='PROG', description='description')
3933 argument_signatures = [Sig('-V', '--version', action='version', version='3.6')]
3934 argument_group_signatures = []
3935 usage = '''\
3936 usage: PROG [-h] [-V]
3937 '''
3938 help = usage + '''\
3939
3940 description
3941
3942 optional arguments:
3943 -h, --help show this help message and exit
3944 -V, --version show program's version number and exit
3945 '''
3946 version = ''
3947
Steven Bethardbc3b1042011-03-27 13:57:55 +02003948class TestHelpSubparsersOrdering(HelpTestCase):
3949 """Test ordering of subcommands in help matches the code"""
3950 parser_signature = Sig(prog='PROG',
3951 description='display some subcommands',
3952 version='0.1')
3953
3954 subparsers_signatures = [Sig(name=name)
3955 for name in ('a', 'b', 'c', 'd', 'e')]
3956
3957 usage = '''\
3958 usage: PROG [-h] [-v] {a,b,c,d,e} ...
3959 '''
3960
3961 help = usage + '''\
3962
3963 display some subcommands
3964
3965 positional arguments:
3966 {a,b,c,d,e}
3967
3968 optional arguments:
3969 -h, --help show this help message and exit
3970 -v, --version show program's version number and exit
3971 '''
3972
3973 version = '''\
3974 0.1
3975 '''
3976
3977class TestHelpSubparsersWithHelpOrdering(HelpTestCase):
3978 """Test ordering of subcommands in help matches the code"""
3979 parser_signature = Sig(prog='PROG',
3980 description='display some subcommands',
3981 version='0.1')
3982
3983 subcommand_data = (('a', 'a subcommand help'),
3984 ('b', 'b subcommand help'),
3985 ('c', 'c subcommand help'),
3986 ('d', 'd subcommand help'),
3987 ('e', 'e subcommand help'),
3988 )
3989
3990 subparsers_signatures = [Sig(name=name, help=help)
3991 for name, help in subcommand_data]
3992
3993 usage = '''\
3994 usage: PROG [-h] [-v] {a,b,c,d,e} ...
3995 '''
3996
3997 help = usage + '''\
3998
3999 display some subcommands
4000
4001 positional arguments:
4002 {a,b,c,d,e}
4003 a a subcommand help
4004 b b subcommand help
4005 c c subcommand help
4006 d d subcommand help
4007 e e subcommand help
4008
4009 optional arguments:
4010 -h, --help show this help message and exit
4011 -v, --version show program's version number and exit
4012 '''
4013
4014 version = '''\
4015 0.1
4016 '''
4017
4018
Benjamin Petersona39e9662010-03-02 22:05:59 +00004019# =====================================
4020# Optional/Positional constructor tests
4021# =====================================
4022
4023class TestInvalidArgumentConstructors(TestCase):
4024 """Test a bunch of invalid Argument constructors"""
4025
4026 def assertTypeError(self, *args, **kwargs):
4027 parser = argparse.ArgumentParser()
4028 self.assertRaises(TypeError, parser.add_argument,
4029 *args, **kwargs)
4030
4031 def assertValueError(self, *args, **kwargs):
4032 parser = argparse.ArgumentParser()
4033 self.assertRaises(ValueError, parser.add_argument,
4034 *args, **kwargs)
4035
4036 def test_invalid_keyword_arguments(self):
4037 self.assertTypeError('-x', bar=None)
4038 self.assertTypeError('-y', callback='foo')
4039 self.assertTypeError('-y', callback_args=())
4040 self.assertTypeError('-y', callback_kwargs={})
4041
4042 def test_missing_destination(self):
4043 self.assertTypeError()
4044 for action in ['append', 'store']:
4045 self.assertTypeError(action=action)
4046
4047 def test_invalid_option_strings(self):
4048 self.assertValueError('--')
4049 self.assertValueError('---')
4050
4051 def test_invalid_type(self):
4052 self.assertValueError('--foo', type='int')
Steven Betharde3c11b42011-04-04 01:47:52 +02004053 self.assertValueError('--foo', type=(int, float))
Benjamin Petersona39e9662010-03-02 22:05:59 +00004054
4055 def test_invalid_action(self):
4056 self.assertValueError('-x', action='foo')
4057 self.assertValueError('foo', action='baz')
Steven Betharde3c11b42011-04-04 01:47:52 +02004058 self.assertValueError('--foo', action=('store', 'append'))
Benjamin Petersona39e9662010-03-02 22:05:59 +00004059 parser = argparse.ArgumentParser()
4060 try:
4061 parser.add_argument("--foo", action="store-true")
4062 except ValueError:
4063 e = sys.exc_info()[1]
4064 expected = 'unknown action'
4065 msg = 'expected %r, found %r' % (expected, e)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004066 self.assertTrue(expected in str(e), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004067
4068 def test_multiple_dest(self):
4069 parser = argparse.ArgumentParser()
4070 parser.add_argument(dest='foo')
4071 try:
4072 parser.add_argument('bar', dest='baz')
4073 except ValueError:
4074 e = sys.exc_info()[1]
4075 expected = 'dest supplied twice for positional argument'
4076 msg = 'expected %r, found %r' % (expected, e)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004077 self.assertTrue(expected in str(e), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004078
4079 def test_no_argument_actions(self):
4080 for action in ['store_const', 'store_true', 'store_false',
4081 'append_const', 'count']:
4082 for attrs in [dict(type=int), dict(nargs='+'),
4083 dict(choices='ab')]:
4084 self.assertTypeError('-x', action=action, **attrs)
4085
4086 def test_no_argument_no_const_actions(self):
4087 # options with zero arguments
4088 for action in ['store_true', 'store_false', 'count']:
4089
4090 # const is always disallowed
4091 self.assertTypeError('-x', const='foo', action=action)
4092
4093 # nargs is always disallowed
4094 self.assertTypeError('-x', nargs='*', action=action)
4095
4096 def test_more_than_one_argument_actions(self):
4097 for action in ['store', 'append']:
4098
4099 # nargs=0 is disallowed
4100 self.assertValueError('-x', nargs=0, action=action)
4101 self.assertValueError('spam', nargs=0, action=action)
4102
4103 # const is disallowed with non-optional arguments
4104 for nargs in [1, '*', '+']:
4105 self.assertValueError('-x', const='foo',
4106 nargs=nargs, action=action)
4107 self.assertValueError('spam', const='foo',
4108 nargs=nargs, action=action)
4109
4110 def test_required_const_actions(self):
4111 for action in ['store_const', 'append_const']:
4112
4113 # nargs is always disallowed
4114 self.assertTypeError('-x', nargs='+', action=action)
4115
4116 def test_parsers_action_missing_params(self):
4117 self.assertTypeError('command', action='parsers')
4118 self.assertTypeError('command', action='parsers', prog='PROG')
4119 self.assertTypeError('command', action='parsers',
4120 parser_class=argparse.ArgumentParser)
4121
4122 def test_required_positional(self):
4123 self.assertTypeError('foo', required=True)
4124
4125 def test_user_defined_action(self):
4126
4127 class Success(Exception):
4128 pass
4129
4130 class Action(object):
4131
4132 def __init__(self,
4133 option_strings,
4134 dest,
4135 const,
4136 default,
4137 required=False):
4138 if dest == 'spam':
4139 if const is Success:
4140 if default is Success:
4141 raise Success()
4142
4143 def __call__(self, *args, **kwargs):
4144 pass
4145
4146 parser = argparse.ArgumentParser()
4147 self.assertRaises(Success, parser.add_argument, '--spam',
4148 action=Action, default=Success, const=Success)
4149 self.assertRaises(Success, parser.add_argument, 'spam',
4150 action=Action, default=Success, const=Success)
4151
4152# ================================
4153# Actions returned by add_argument
4154# ================================
4155
4156class TestActionsReturned(TestCase):
4157
4158 def test_dest(self):
4159 parser = argparse.ArgumentParser()
4160 action = parser.add_argument('--foo')
4161 self.assertEqual(action.dest, 'foo')
4162 action = parser.add_argument('-b', '--bar')
4163 self.assertEqual(action.dest, 'bar')
4164 action = parser.add_argument('-x', '-y')
4165 self.assertEqual(action.dest, 'x')
4166
4167 def test_misc(self):
4168 parser = argparse.ArgumentParser()
4169 action = parser.add_argument('--foo', nargs='?', const=42,
4170 default=84, type=int, choices=[1, 2],
4171 help='FOO', metavar='BAR', dest='baz')
4172 self.assertEqual(action.nargs, '?')
4173 self.assertEqual(action.const, 42)
4174 self.assertEqual(action.default, 84)
4175 self.assertEqual(action.type, int)
4176 self.assertEqual(action.choices, [1, 2])
4177 self.assertEqual(action.help, 'FOO')
4178 self.assertEqual(action.metavar, 'BAR')
4179 self.assertEqual(action.dest, 'baz')
4180
4181
4182# ================================
4183# Argument conflict handling tests
4184# ================================
4185
4186class TestConflictHandling(TestCase):
4187
4188 def test_bad_type(self):
4189 self.assertRaises(ValueError, argparse.ArgumentParser,
4190 conflict_handler='foo')
4191
4192 def test_conflict_error(self):
4193 parser = argparse.ArgumentParser()
4194 parser.add_argument('-x')
4195 self.assertRaises(argparse.ArgumentError,
4196 parser.add_argument, '-x')
4197 parser.add_argument('--spam')
4198 self.assertRaises(argparse.ArgumentError,
4199 parser.add_argument, '--spam')
4200
4201 def test_resolve_error(self):
4202 get_parser = argparse.ArgumentParser
4203 parser = get_parser(prog='PROG', conflict_handler='resolve')
4204
4205 parser.add_argument('-x', help='OLD X')
4206 parser.add_argument('-x', help='NEW X')
4207 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4208 usage: PROG [-h] [-x X]
4209
4210 optional arguments:
4211 -h, --help show this help message and exit
4212 -x X NEW X
4213 '''))
4214
4215 parser.add_argument('--spam', metavar='OLD_SPAM')
4216 parser.add_argument('--spam', metavar='NEW_SPAM')
4217 self.assertEqual(parser.format_help(), textwrap.dedent('''\
4218 usage: PROG [-h] [-x X] [--spam NEW_SPAM]
4219
4220 optional arguments:
4221 -h, --help show this help message and exit
4222 -x X NEW X
4223 --spam NEW_SPAM
4224 '''))
4225
4226
4227# =============================
4228# Help and Version option tests
4229# =============================
4230
4231class TestOptionalsHelpVersionActions(TestCase):
4232 """Test the help and version actions"""
4233
4234 def _get_error(self, func, *args, **kwargs):
4235 try:
4236 func(*args, **kwargs)
4237 except ArgumentParserError:
4238 return sys.exc_info()[1]
4239 else:
4240 self.assertRaises(ArgumentParserError, func, *args, **kwargs)
4241
4242 def assertPrintHelpExit(self, parser, args_str):
4243 self.assertEqual(
4244 parser.format_help(),
4245 self._get_error(parser.parse_args, args_str.split()).stdout)
4246
4247 def assertPrintVersionExit(self, parser, args_str):
4248 self.assertEqual(
4249 parser.format_version(),
4250 self._get_error(parser.parse_args, args_str.split()).stderr)
4251
4252 def assertArgumentParserError(self, parser, *args):
4253 self.assertRaises(ArgumentParserError, parser.parse_args, args)
4254
4255 def test_version(self):
4256 parser = ErrorRaisingArgumentParser(version='1.0')
4257 self.assertPrintHelpExit(parser, '-h')
4258 self.assertPrintHelpExit(parser, '--help')
4259 self.assertPrintVersionExit(parser, '-v')
4260 self.assertPrintVersionExit(parser, '--version')
4261
4262 def test_version_format(self):
4263 parser = ErrorRaisingArgumentParser(prog='PPP', version='%(prog)s 3.5')
4264 msg = self._get_error(parser.parse_args, ['-v']).stderr
4265 self.assertEqual('PPP 3.5\n', msg)
4266
4267 def test_version_no_help(self):
4268 parser = ErrorRaisingArgumentParser(add_help=False, version='1.0')
4269 self.assertArgumentParserError(parser, '-h')
4270 self.assertArgumentParserError(parser, '--help')
4271 self.assertPrintVersionExit(parser, '-v')
4272 self.assertPrintVersionExit(parser, '--version')
4273
4274 def test_version_action(self):
4275 parser = ErrorRaisingArgumentParser(prog='XXX')
4276 parser.add_argument('-V', action='version', version='%(prog)s 3.7')
4277 msg = self._get_error(parser.parse_args, ['-V']).stderr
4278 self.assertEqual('XXX 3.7\n', msg)
4279
4280 def test_no_help(self):
4281 parser = ErrorRaisingArgumentParser(add_help=False)
4282 self.assertArgumentParserError(parser, '-h')
4283 self.assertArgumentParserError(parser, '--help')
4284 self.assertArgumentParserError(parser, '-v')
4285 self.assertArgumentParserError(parser, '--version')
4286
4287 def test_alternate_help_version(self):
4288 parser = ErrorRaisingArgumentParser()
4289 parser.add_argument('-x', action='help')
4290 parser.add_argument('-y', action='version')
4291 self.assertPrintHelpExit(parser, '-x')
4292 self.assertPrintVersionExit(parser, '-y')
4293 self.assertArgumentParserError(parser, '-v')
4294 self.assertArgumentParserError(parser, '--version')
4295
4296 def test_help_version_extra_arguments(self):
4297 parser = ErrorRaisingArgumentParser(version='1.0')
4298 parser.add_argument('-x', action='store_true')
4299 parser.add_argument('y')
4300
4301 # try all combinations of valid prefixes and suffixes
4302 valid_prefixes = ['', '-x', 'foo', '-x bar', 'baz -x']
4303 valid_suffixes = valid_prefixes + ['--bad-option', 'foo bar baz']
4304 for prefix in valid_prefixes:
4305 for suffix in valid_suffixes:
4306 format = '%s %%s %s' % (prefix, suffix)
4307 self.assertPrintHelpExit(parser, format % '-h')
4308 self.assertPrintHelpExit(parser, format % '--help')
4309 self.assertPrintVersionExit(parser, format % '-v')
4310 self.assertPrintVersionExit(parser, format % '--version')
4311
4312
4313# ======================
4314# str() and repr() tests
4315# ======================
4316
4317class TestStrings(TestCase):
4318 """Test str() and repr() on Optionals and Positionals"""
4319
4320 def assertStringEqual(self, obj, result_string):
4321 for func in [str, repr]:
4322 self.assertEqual(func(obj), result_string)
4323
4324 def test_optional(self):
4325 option = argparse.Action(
4326 option_strings=['--foo', '-a', '-b'],
4327 dest='b',
4328 type='int',
4329 nargs='+',
4330 default=42,
4331 choices=[1, 2, 3],
4332 help='HELP',
4333 metavar='METAVAR')
4334 string = (
4335 "Action(option_strings=['--foo', '-a', '-b'], dest='b', "
4336 "nargs='+', const=None, default=42, type='int', "
4337 "choices=[1, 2, 3], help='HELP', metavar='METAVAR')")
4338 self.assertStringEqual(option, string)
4339
4340 def test_argument(self):
4341 argument = argparse.Action(
4342 option_strings=[],
4343 dest='x',
4344 type=float,
4345 nargs='?',
4346 default=2.5,
4347 choices=[0.5, 1.5, 2.5],
4348 help='H HH H',
4349 metavar='MV MV MV')
4350 string = (
4351 "Action(option_strings=[], dest='x', nargs='?', "
4352 "const=None, default=2.5, type=%r, choices=[0.5, 1.5, 2.5], "
4353 "help='H HH H', metavar='MV MV MV')" % float)
4354 self.assertStringEqual(argument, string)
4355
4356 def test_namespace(self):
4357 ns = argparse.Namespace(foo=42, bar='spam')
4358 string = "Namespace(bar='spam', foo=42)"
4359 self.assertStringEqual(ns, string)
4360
4361 def test_parser(self):
4362 parser = argparse.ArgumentParser(prog='PROG')
4363 string = (
4364 "ArgumentParser(prog='PROG', usage=None, description=None, "
4365 "version=None, formatter_class=%r, conflict_handler='error', "
4366 "add_help=True)" % argparse.HelpFormatter)
4367 self.assertStringEqual(parser, string)
4368
4369# ===============
4370# Namespace tests
4371# ===============
4372
4373class TestNamespace(TestCase):
4374
4375 def test_constructor(self):
4376 ns = argparse.Namespace()
4377 self.assertRaises(AttributeError, getattr, ns, 'x')
4378
4379 ns = argparse.Namespace(a=42, b='spam')
4380 self.assertEqual(ns.a, 42)
4381 self.assertEqual(ns.b, 'spam')
4382
4383 def test_equality(self):
4384 ns1 = argparse.Namespace(a=1, b=2)
4385 ns2 = argparse.Namespace(b=2, a=1)
4386 ns3 = argparse.Namespace(a=1)
4387 ns4 = argparse.Namespace(b=2)
4388
4389 self.assertEqual(ns1, ns2)
4390 self.assertNotEqual(ns1, ns3)
4391 self.assertNotEqual(ns1, ns4)
4392 self.assertNotEqual(ns2, ns3)
4393 self.assertNotEqual(ns2, ns4)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004394 self.assertTrue(ns1 != ns3)
4395 self.assertTrue(ns1 != ns4)
4396 self.assertTrue(ns2 != ns3)
4397 self.assertTrue(ns2 != ns4)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004398
4399
4400# ===================
4401# File encoding tests
4402# ===================
4403
4404class TestEncoding(TestCase):
4405
4406 def _test_module_encoding(self, path):
4407 path, _ = os.path.splitext(path)
4408 path += ".py"
Antoine Pitrouf7c24452010-10-14 21:22:52 +00004409 with codecs.open(path, 'r', 'utf8') as f:
4410 f.read()
Benjamin Petersona39e9662010-03-02 22:05:59 +00004411
4412 def test_argparse_module_encoding(self):
4413 self._test_module_encoding(argparse.__file__)
4414
4415 def test_test_argparse_module_encoding(self):
4416 self._test_module_encoding(__file__)
4417
4418# ===================
4419# ArgumentError tests
4420# ===================
4421
4422class TestArgumentError(TestCase):
4423
4424 def test_argument_error(self):
4425 msg = "my error here"
4426 error = argparse.ArgumentError(None, msg)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004427 self.assertEqual(str(error), msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004428
4429# =======================
4430# ArgumentTypeError tests
4431# =======================
4432
R. David Murray561b96f2011-02-11 17:25:54 +00004433class TestArgumentTypeError(TestCase):
Benjamin Petersona39e9662010-03-02 22:05:59 +00004434
4435 def test_argument_type_error(self):
4436
4437 def spam(string):
4438 raise argparse.ArgumentTypeError('spam!')
4439
4440 parser = ErrorRaisingArgumentParser(prog='PROG', add_help=False)
4441 parser.add_argument('x', type=spam)
4442 try:
4443 parser.parse_args(['XXX'])
4444 except ArgumentParserError:
4445 expected = 'usage: PROG x\nPROG: error: argument x: spam!\n'
4446 msg = sys.exc_info()[1].stderr
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004447 self.assertEqual(expected, msg)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004448 else:
4449 self.fail()
4450
R David Murray20101872012-08-31 23:15:28 -04004451# ================================================
4452# Check that the type function is called only once
4453# ================================================
4454
4455class TestTypeFunctionCallOnlyOnce(TestCase):
4456
4457 def test_type_function_call_only_once(self):
4458 def spam(string_to_convert):
4459 self.assertEqual(string_to_convert, 'spam!')
4460 return 'foo_converted'
4461
4462 parser = argparse.ArgumentParser()
4463 parser.add_argument('--foo', type=spam, default='bar')
4464 args = parser.parse_args('--foo spam!'.split())
4465 self.assertEqual(NS(foo='foo_converted'), args)
4466
4467# ================================================================
4468# Check that the type function is called with a non-string default
4469# ================================================================
4470
4471class TestTypeFunctionCallWithNonStringDefault(TestCase):
4472
4473 def test_type_function_call_with_non_string_default(self):
4474 def spam(int_to_convert):
4475 self.assertEqual(int_to_convert, 0)
4476 return 'foo_converted'
4477
4478 parser = argparse.ArgumentParser()
4479 parser.add_argument('--foo', type=spam, default=0)
4480 args = parser.parse_args([])
4481 self.assertEqual(NS(foo='foo_converted'), args)
4482
Benjamin Petersona39e9662010-03-02 22:05:59 +00004483# ======================
4484# parse_known_args tests
4485# ======================
4486
4487class TestParseKnownArgs(TestCase):
4488
R David Murraya99c7de2012-09-08 12:15:25 -04004489 def test_arguments_tuple(self):
4490 parser = argparse.ArgumentParser()
4491 parser.parse_args(())
4492
4493 def test_arguments_list(self):
4494 parser = argparse.ArgumentParser()
4495 parser.parse_args([])
4496
4497 def test_arguments_tuple_positional(self):
4498 parser = argparse.ArgumentParser()
4499 parser.add_argument('x')
4500 parser.parse_args(('x',))
4501
4502 def test_arguments_list_positional(self):
4503 parser = argparse.ArgumentParser()
4504 parser.add_argument('x')
4505 parser.parse_args(['x'])
4506
Benjamin Petersona39e9662010-03-02 22:05:59 +00004507 def test_optionals(self):
4508 parser = argparse.ArgumentParser()
4509 parser.add_argument('--foo')
4510 args, extras = parser.parse_known_args('--foo F --bar --baz'.split())
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004511 self.assertEqual(NS(foo='F'), args)
4512 self.assertEqual(['--bar', '--baz'], extras)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004513
4514 def test_mixed(self):
4515 parser = argparse.ArgumentParser()
4516 parser.add_argument('-v', nargs='?', const=1, type=int)
4517 parser.add_argument('--spam', action='store_false')
4518 parser.add_argument('badger')
4519
4520 argv = ["B", "C", "--foo", "-v", "3", "4"]
4521 args, extras = parser.parse_known_args(argv)
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004522 self.assertEqual(NS(v=3, spam=True, badger="B"), args)
4523 self.assertEqual(["C", "--foo", "4"], extras)
Benjamin Petersona39e9662010-03-02 22:05:59 +00004524
Steven Bethard53958622011-03-26 17:57:52 +01004525# ==========================
4526# add_argument metavar tests
4527# ==========================
4528
4529class TestAddArgumentMetavar(TestCase):
4530
4531 EXPECTED_MESSAGE = "length of metavar tuple does not match nargs"
4532
4533 def do_test_no_exception(self, nargs, metavar):
4534 parser = argparse.ArgumentParser()
4535 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4536
4537 def do_test_exception(self, nargs, metavar):
4538 parser = argparse.ArgumentParser()
4539 with self.assertRaises(ValueError) as cm:
4540 parser.add_argument("--foo", nargs=nargs, metavar=metavar)
4541 self.assertEqual(cm.exception.args[0], self.EXPECTED_MESSAGE)
4542
4543 # Unit tests for different values of metavar when nargs=None
4544
4545 def test_nargs_None_metavar_string(self):
4546 self.do_test_no_exception(nargs=None, metavar="1")
4547
4548 def test_nargs_None_metavar_length0(self):
4549 self.do_test_exception(nargs=None, metavar=tuple())
4550
4551 def test_nargs_None_metavar_length1(self):
4552 self.do_test_no_exception(nargs=None, metavar=("1"))
4553
4554 def test_nargs_None_metavar_length2(self):
4555 self.do_test_exception(nargs=None, metavar=("1", "2"))
4556
4557 def test_nargs_None_metavar_length3(self):
4558 self.do_test_exception(nargs=None, metavar=("1", "2", "3"))
4559
4560 # Unit tests for different values of metavar when nargs=?
4561
4562 def test_nargs_optional_metavar_string(self):
4563 self.do_test_no_exception(nargs="?", metavar="1")
4564
4565 def test_nargs_optional_metavar_length0(self):
4566 self.do_test_exception(nargs="?", metavar=tuple())
4567
4568 def test_nargs_optional_metavar_length1(self):
4569 self.do_test_no_exception(nargs="?", metavar=("1"))
4570
4571 def test_nargs_optional_metavar_length2(self):
4572 self.do_test_exception(nargs="?", metavar=("1", "2"))
4573
4574 def test_nargs_optional_metavar_length3(self):
4575 self.do_test_exception(nargs="?", metavar=("1", "2", "3"))
4576
4577 # Unit tests for different values of metavar when nargs=*
4578
4579 def test_nargs_zeroormore_metavar_string(self):
4580 self.do_test_no_exception(nargs="*", metavar="1")
4581
4582 def test_nargs_zeroormore_metavar_length0(self):
4583 self.do_test_exception(nargs="*", metavar=tuple())
4584
4585 def test_nargs_zeroormore_metavar_length1(self):
4586 self.do_test_no_exception(nargs="*", metavar=("1"))
4587
4588 def test_nargs_zeroormore_metavar_length2(self):
4589 self.do_test_no_exception(nargs="*", metavar=("1", "2"))
4590
4591 def test_nargs_zeroormore_metavar_length3(self):
4592 self.do_test_exception(nargs="*", metavar=("1", "2", "3"))
4593
4594 # Unit tests for different values of metavar when nargs=+
4595
4596 def test_nargs_oneormore_metavar_string(self):
4597 self.do_test_no_exception(nargs="+", metavar="1")
4598
4599 def test_nargs_oneormore_metavar_length0(self):
4600 self.do_test_exception(nargs="+", metavar=tuple())
4601
4602 def test_nargs_oneormore_metavar_length1(self):
4603 self.do_test_no_exception(nargs="+", metavar=("1"))
4604
4605 def test_nargs_oneormore_metavar_length2(self):
4606 self.do_test_no_exception(nargs="+", metavar=("1", "2"))
4607
4608 def test_nargs_oneormore_metavar_length3(self):
4609 self.do_test_exception(nargs="+", metavar=("1", "2", "3"))
4610
4611 # Unit tests for different values of metavar when nargs=...
4612
4613 def test_nargs_remainder_metavar_string(self):
4614 self.do_test_no_exception(nargs="...", metavar="1")
4615
4616 def test_nargs_remainder_metavar_length0(self):
4617 self.do_test_no_exception(nargs="...", metavar=tuple())
4618
4619 def test_nargs_remainder_metavar_length1(self):
4620 self.do_test_no_exception(nargs="...", metavar=("1"))
4621
4622 def test_nargs_remainder_metavar_length2(self):
4623 self.do_test_no_exception(nargs="...", metavar=("1", "2"))
4624
4625 def test_nargs_remainder_metavar_length3(self):
4626 self.do_test_no_exception(nargs="...", metavar=("1", "2", "3"))
4627
4628 # Unit tests for different values of metavar when nargs=A...
4629
4630 def test_nargs_parser_metavar_string(self):
4631 self.do_test_no_exception(nargs="A...", metavar="1")
4632
4633 def test_nargs_parser_metavar_length0(self):
4634 self.do_test_exception(nargs="A...", metavar=tuple())
4635
4636 def test_nargs_parser_metavar_length1(self):
4637 self.do_test_no_exception(nargs="A...", metavar=("1"))
4638
4639 def test_nargs_parser_metavar_length2(self):
4640 self.do_test_exception(nargs="A...", metavar=("1", "2"))
4641
4642 def test_nargs_parser_metavar_length3(self):
4643 self.do_test_exception(nargs="A...", metavar=("1", "2", "3"))
4644
4645 # Unit tests for different values of metavar when nargs=1
4646
4647 def test_nargs_1_metavar_string(self):
4648 self.do_test_no_exception(nargs=1, metavar="1")
4649
4650 def test_nargs_1_metavar_length0(self):
4651 self.do_test_exception(nargs=1, metavar=tuple())
4652
4653 def test_nargs_1_metavar_length1(self):
4654 self.do_test_no_exception(nargs=1, metavar=("1"))
4655
4656 def test_nargs_1_metavar_length2(self):
4657 self.do_test_exception(nargs=1, metavar=("1", "2"))
4658
4659 def test_nargs_1_metavar_length3(self):
4660 self.do_test_exception(nargs=1, metavar=("1", "2", "3"))
4661
4662 # Unit tests for different values of metavar when nargs=2
4663
4664 def test_nargs_2_metavar_string(self):
4665 self.do_test_no_exception(nargs=2, metavar="1")
4666
4667 def test_nargs_2_metavar_length0(self):
4668 self.do_test_exception(nargs=2, metavar=tuple())
4669
4670 def test_nargs_2_metavar_length1(self):
4671 self.do_test_no_exception(nargs=2, metavar=("1"))
4672
4673 def test_nargs_2_metavar_length2(self):
4674 self.do_test_no_exception(nargs=2, metavar=("1", "2"))
4675
4676 def test_nargs_2_metavar_length3(self):
4677 self.do_test_exception(nargs=2, metavar=("1", "2", "3"))
4678
4679 # Unit tests for different values of metavar when nargs=3
4680
4681 def test_nargs_3_metavar_string(self):
4682 self.do_test_no_exception(nargs=3, metavar="1")
4683
4684 def test_nargs_3_metavar_length0(self):
4685 self.do_test_exception(nargs=3, metavar=tuple())
4686
4687 def test_nargs_3_metavar_length1(self):
4688 self.do_test_no_exception(nargs=3, metavar=("1"))
4689
4690 def test_nargs_3_metavar_length2(self):
4691 self.do_test_exception(nargs=3, metavar=("1", "2"))
4692
4693 def test_nargs_3_metavar_length3(self):
4694 self.do_test_no_exception(nargs=3, metavar=("1", "2", "3"))
4695
Benjamin Petersona39e9662010-03-02 22:05:59 +00004696# ============================
4697# from argparse import * tests
4698# ============================
4699
4700class TestImportStar(TestCase):
4701
4702 def test(self):
4703 for name in argparse.__all__:
Benjamin Petersonfa31eaa2010-03-02 22:26:25 +00004704 self.assertTrue(hasattr(argparse, name))
Benjamin Petersona39e9662010-03-02 22:05:59 +00004705
Steven Bethard931906a2010-11-01 15:24:42 +00004706 def test_all_exports_everything_but_modules(self):
4707 items = [
4708 name
4709 for name, value in vars(argparse).items()
4710 if not name.startswith("_")
4711 if not inspect.ismodule(value)
4712 ]
4713 self.assertEqual(sorted(items), sorted(argparse.__all__))
4714
Benjamin Peterson036fae32010-03-02 22:20:10 +00004715def test_main():
Florent Xicluna6257a7b2010-03-31 22:01:03 +00004716 # silence warnings about version argument - these are expected
4717 with test_support.check_warnings(
4718 ('The "version" argument to ArgumentParser is deprecated.',
4719 DeprecationWarning),
4720 ('The (format|print)_version method is deprecated',
4721 DeprecationWarning)):
Benjamin Peterson4aa8a132010-03-02 22:23:33 +00004722 test_support.run_unittest(__name__)
Benjamin Peterson842b95b2010-03-02 23:43:47 +00004723 # Remove global references to avoid looking like we have refleaks.
4724 RFile.seen = {}
4725 WFile.seen = set()
4726
Benjamin Peterson036fae32010-03-02 22:20:10 +00004727
Benjamin Petersona39e9662010-03-02 22:05:59 +00004728
4729if __name__ == '__main__':
Benjamin Petersone4d90c22010-03-02 22:24:30 +00004730 test_main()