github.com/grumpyhome/grumpy@v0.3.1-0.20201208125205-7b775405bdf1/grumpy-runtime-src/third_party/stdlib/test/test_argparse.py (about)

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