diff -r 2cd0aa44d53c Lib/test/test_argparse.py --- a/Lib/test/test_argparse.py Wed Jan 21 00:47:54 2015 -0500 +++ b/Lib/test/test_argparse.py Thu Jan 22 02:49:22 2015 +0000 @@ -439,7 +439,8 @@ Sig('::bar'), Sig('/baz', action='store_const', const=42), ] - failures = ['--bar', '-fbar', '-b B', 'B', '-f', '--bar B', '-baz', '-h', '--help', '+h', '::help', '/help'] + failures = ['--bar', '-fbar', '-b B', 'B', '-f', '--bar B', + '-baz', '-h', '--help', '+h', '::help', '/help'] successes = [ ('', NS(f=False, bar=None, baz=None)), ('+f', NS(f=True, bar=None, baz=None)), @@ -1891,8 +1892,6 @@ -h, --help show this help message and exit ++foo foo help ''')) - - def test_help_alternate_prefix_chars(self): parser = self._get_parser(prefix_chars='+:/') self.assertEqual(parser.format_usage(), @@ -2196,20 +2195,29 @@ m = parent.add_mutually_exclusive_group() m.add_argument('-y') m.add_argument('-z') + d = parent.add_mutually_dependence_group() + d.add_argument('-a') + d.add_argument('-b') parser = ErrorRaisingArgumentParser(parents=[parent]) self.assertRaises(ArgumentParserError, parser.parse_args, - ['-y', 'Y', '-z', 'Z']) + ['-y', 'Y', '-z', 'Z']) + self.assertRaises(ArgumentParserError, parser.parse_args, + ['a', 'A']) + self.assertRaises(ArgumentParserError, parser.parse_args, + ['b', 'B']) parser_help = parser.format_help() progname = self.main_program self.assertEqual(parser_help, textwrap.dedent('''\ - usage: {}{}[-h] [-w W] [-x X] [-y Y | -z Z] + usage: {}{}[-h] [-w W] [-x X] [-y Y | -z Z] [-a A & -b B] optional arguments: -h, --help show this help message and exit -y Y -z Z + -a A + -b B g: gd @@ -2260,6 +2268,51 @@ ''' self.assertEqual(parser.format_help(), textwrap.dedent(expected)) +# ============================== +# Mutually dependence group tests +# ============================== + + +class TestMutuallyDependenceGroupErrors(TestCase): + + def test_invalid_add_argument_group(self): + parser = ErrorRaisingArgumentParser() + raises = self.assertRaises + raises(TypeError, parser.add_mutually_dependence_group, title='foo') + + def test_invalid_add_argument(self): + parser = ErrorRaisingArgumentParser() + group = parser.add_mutually_dependence_group() + add_argument = group.add_argument + raises = self.assertRaises + raises(ValueError, add_argument, '--foo', required=True) + raises(ValueError, add_argument, 'bar') + raises(ValueError, add_argument, 'bar', nargs='+') + raises(ValueError, add_argument, 'bar', nargs=1) + raises(ValueError, add_argument, 'bar', nargs=argparse.PARSER) + raises(ValueError, add_argument, '--foo', action='store_true') + + def test_help(self): + parser = ErrorRaisingArgumentParser(prog='PROG') + group1 = parser.add_mutually_dependence_group() + group1.add_argument('--foo') + group1.add_argument('--bar') + group2 = parser.add_mutually_dependence_group() + group2.add_argument('--soup') + group2.add_argument('--nuts') + expected = '''\ + usage: PROG [-h] [--foo FOO & --bar BAR] [--soup SOUP & --nuts NUTS] + + optional arguments: + -h, --help show this help message and exit + --foo FOO + --bar BAR + --soup SOUP + --nuts NUTS + ''' + self.assertEqual(parser.format_help(), textwrap.dedent(expected)) + + class MEMixin(object): def test_failures_when_not_required(self): @@ -2343,6 +2396,39 @@ ''' +class TestMutuallyDependenceSimple(MEMixin, TestCase): + + def get_parser(self, required=None): + parser = ErrorRaisingArgumentParser(prog='PROG') + group = parser.add_mutually_dependence_group(required=required) + group.add_argument('--bar', help='bar help') + group.add_argument('--baz', nargs='?', const='Z', help='baz help') + return parser + + failures = ['--bar X', '--baz Z'] + successes = [ + ('--bar X --baz Z', NS(bar='X', baz='Z')), + ('--bar X --bar Y --baz Z', NS(bar='Y', baz='Z')), + ] + successes_when_not_required = [ + ('', NS(bar=None, baz=None)), + ] + + usage_when_not_required = '''\ + usage: PROG [-h] [--bar BAR & --baz [BAZ]] + ''' + usage_when_required = '''\ + usage: PROG [-h] (--bar BAR & --baz [BAZ]) + ''' + help = '''\ + + optional arguments: + -h, --help show this help message and exit + --bar BAR bar help + --baz [BAZ] baz help + ''' + + class TestMutuallyExclusiveLong(MEMixin, TestCase): def get_parser(self, required=None): @@ -2386,6 +2472,49 @@ ''' +class TestMutuallyDependenceLong(MEMixin, TestCase): + + def get_parser(self, required=None): + parser = ErrorRaisingArgumentParser(prog='PROG') + parser.add_argument('--abcde', help='abcde help') + parser.add_argument('--fghij', help='fghij help') + group = parser.add_mutually_dependence_group(required=required) + group.add_argument('--klmno', help='klmno help') + group.add_argument('--pqrst', help='pqrst help') + return parser + + failures = ['--klmno X', '--pqrst Y'] + successes = [ + ('--klmno X --pqrst Y', + NS(abcde=None, fghij=None, klmno='X', pqrst='Y')), + ('--abcde Y --klmno X --pqrst Z', + NS(abcde='Y', fghij=None, klmno='X', pqrst='Z')), + ('--klmno X --pqrst Y --fghij Z', + NS(abcde=None, fghij='Z', klmno='X', pqrst='Y')), + ] + successes_when_not_required = [ + ('', NS(abcde=None, fghij=None, klmno=None, pqrst=None)), + ] + + usage_when_not_required = '''\ + usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ] + [--klmno KLMNO & --pqrst PQRST] + ''' + usage_when_required = '''\ + usage: PROG [-h] [--abcde ABCDE] [--fghij FGHIJ] + (--klmno KLMNO & --pqrst PQRST) + ''' + help = '''\ + + optional arguments: + -h, --help show this help message and exit + --abcde ABCDE abcde help + --fghij FGHIJ fghij help + --klmno KLMNO klmno help + --pqrst PQRST pqrst help + ''' + + class TestMutuallyExclusiveFirstSuppressed(MEMixin, TestCase): def get_parser(self, required): @@ -2419,6 +2548,38 @@ ''' +class TestMutuallyDependenceFirstSuppressed(MEMixin, TestCase): + + def get_parser(self, required): + parser = ErrorRaisingArgumentParser(prog='PROG') + group = parser.add_mutually_dependence_group(required=required) + group.add_argument('-x', help=argparse.SUPPRESS) + group.add_argument('-y', help='y help') + return parser + + failures = ['-x', '-y'] + successes = [ + ('-x X -y Y', NS(x='X', y='Y')), + ('-x X -y Y -y Z', NS(x='X', y='Z')), + ] + successes_when_not_required = [ + ('', NS(x=None, y=None)), + ] + + usage_when_not_required = '''\ + usage: PROG [-h] [-y Y] + ''' + usage_when_required = '''\ + usage: PROG [-h] -y Y + ''' + help = '''\ + + optional arguments: + -h, --help show this help message and exit + -y Y y help + ''' + + class TestMutuallyExclusiveManySuppressed(MEMixin, TestCase): def get_parser(self, required): @@ -2455,6 +2616,42 @@ ''' +class TestMutuallyDependenceManySuppressed(MEMixin, TestCase): + + def get_parser(self, required): + parser = ErrorRaisingArgumentParser(prog='PROG') + group = parser.add_mutually_dependence_group(required=required) + add = group.add_argument + add('--spam', help=argparse.SUPPRESS) + add('--badger', help=argparse.SUPPRESS) + add('--bladder', help=argparse.SUPPRESS) + return parser + + failures = [ + '--spam sp --badger ba', + '--badger ba --bladder bl', + '--bladder bl --spam sp', + ] + successes = [ + ('--spam sp --badger ba --bladder bl', + NS(spam='sp', badger='ba', bladder='bl')), + ('--spam sp --bladder bl --badger ba', + NS(spam='sp', badger='ba', bladder='bl')), + ] + successes_when_not_required = [ + ('', NS(spam=None, badger=None, bladder=None)), + ] + + usage_when_required = usage_when_not_required = '''\ + usage: PROG [-h] + ''' + help = '''\ + + optional arguments: + -h, --help show this help message and exit + ''' + + class TestMutuallyExclusiveOptionalAndPositional(MEMixin, TestCase): def get_parser(self, required): @@ -2500,6 +2697,51 @@ ''' +class TestMutuallyDependenceOptionalAndPositional(MEMixin, TestCase): + + def get_parser(self, required): + parser = ErrorRaisingArgumentParser(prog='PROG') + group = parser.add_mutually_dependence_group(required=required) + group.add_argument('--foo', help='FOO') + group.add_argument('--spam', help='SPAM') + group.add_argument('badger', nargs='*', default='X', help='BADGER') + return parser + + failures = [ + '--spam S X', + 'X --foo F', + 'X Y Z --spam S', + '--foo F X Y', + ] + successes = [ + ('--foo F --spam S', NS(foo='F', spam='S', badger='X')), + ('X --foo F --spam S', + NS(foo='F', spam='S', badger=['X'])), + ('X Y Z --foo F --spam S', + NS(foo='F', spam='S', badger=['X', 'Y', 'Z'])), + ] + successes_when_not_required = [ + ('', NS(foo=None, spam=None, badger='X')), + ] + + usage_when_not_required = '''\ + usage: PROG [-h] [--foo FOO & --spam SPAM & badger [badger ...]] + ''' + usage_when_required = '''\ + usage: PROG [-h] (--foo FOO & --spam SPAM & badger [badger ...]) + ''' + help = '''\ + + positional arguments: + badger BADGER + + optional arguments: + -h, --help show this help message and exit + --foo FOO FOO + --spam SPAM SPAM + ''' + + class TestMutuallyExclusiveOptionalsMixed(MEMixin, TestCase): def get_parser(self, required): @@ -2542,6 +2784,46 @@ ''' +class TestMutuallyDependenceOptionalsMixed(MEMixin, TestCase): + + def get_parser(self, required): + parser = ErrorRaisingArgumentParser(prog='PROG') + parser.add_argument('-x', action='store_true', help='x help') + group = parser.add_mutually_dependence_group(required=required) + group.add_argument('-a', help='a help') + group.add_argument('-b', help='b help') + parser.add_argument('-y', action='store_true', help='y help') + group.add_argument('-c', help='c help') + return parser + + failures = ['-a A-b B', '-b B -c C', '-a A -c C', '-c C -a A'] + successes = [ + ('-a A -b B -c C', NS(a='A', b='B', c='C', x=False, y=False)), + ('-x -a A -b B -c C', NS(a='A', b='B', c='C', x=True, y=False)), + ('-x -y -a A -b B -c C', NS(a='A', b='B', c='C', x=True, y=True)), + ] + successes_when_not_required = [ + ('', NS(a=None, b=None, c=None, x=False, y=False)), + ('-x', NS(a=None, b=None, c=None, x=True, y=False)), + ('-y', NS(a=None, b=None, c=None, x=False, y=True)), + ('-x -y', NS(a=None, b=None, c=None, x=True, y=True)), + ] + + usage_when_required = usage_when_not_required = '''\ + usage: PROG [-h] [-x] [-a A] [-b B] [-y] [-c C] + ''' + help = '''\ + + optional arguments: + -h, --help show this help message and exit + -x x help + -a A a help + -b B b help + -y y help + -c C c help + ''' + + class TestMutuallyExclusiveInGroup(MEMixin, TestCase): def get_parser(self, required=None): @@ -2582,6 +2864,45 @@ ''' +class TestMutuallyDependenceInGroup(MEMixin, TestCase): + + def get_parser(self, required=None): + parser = ErrorRaisingArgumentParser(prog='PROG') + titled_group = parser.add_argument_group( + title='Titled group', description='Group description') + mutex_group = \ + titled_group.add_mutually_dependence_group(required=required) + mutex_group.add_argument('--bar', help='bar help') + mutex_group.add_argument('--baz', help='baz help') + return parser + + failures = ['--baz Y', '--bar Y'] + successes = [ + ('--bar X --baz Y', NS(bar='X', baz='Y')), + ] + successes_when_not_required = [ + ('', NS(bar=None, baz=None)), + ] + + usage_when_not_required = '''\ + usage: PROG [-h] [--bar BAR & --baz BAZ] + ''' + usage_when_required = '''\ + usage: PROG [-h] (--bar BAR & --baz BAZ) + ''' + help = '''\ + + optional arguments: + -h, --help show this help message and exit + + Titled group: + Group description + + --bar BAR bar help + --baz BAZ baz help + ''' + + class TestMutuallyExclusiveOptionalsAndPositionalsMixed(MEMixin, TestCase): def get_parser(self, required): @@ -2623,6 +2944,45 @@ -c c help ''' + +class TestMutuallyDependenceOptionalsAndPositionalsMixed(MEMixin, TestCase): + + def get_parser(self, required): + parser = ErrorRaisingArgumentParser(prog='PROG') + parser.add_argument('x', help='x help') + parser.add_argument('-y', action='store_true', help='y help') + group = parser.add_mutually_dependence_group(required=required) + group.add_argument('a', nargs='?', help='a help') + group.add_argument('-b', help='b help') + group.add_argument('-c', help='c help') + return parser + + failures = ['X A -b B', '-b B -c C', '-c C X A'] + successes = [ + ('X A -b B -c C', NS(a='A', b='B', c='C', x='X', y=False)), + ('X A -y -b B -c C', NS(a='A', b='B', c='C', x='X', y=True)), + ] + successes_when_not_required = [ + ('X', NS(a=None, b=None, c=None, x='X', y=False)), + ('X -y', NS(a=None, b=None, c=None, x='X', y=True)), + ] + + usage_when_required = usage_when_not_required = '''\ + usage: PROG [-h] [-y] [-b B] [-c C] x [a] + ''' + help = '''\ + + positional arguments: + x x help + a a help + + optional arguments: + -h, --help show this help message and exit + -y y help + -b B b help + -c C c help + ''' + # ================================================= # Mutually exclusive group in parent parser tests # ================================================= @@ -2641,6 +3001,11 @@ pass +class TestMutuallyDependenceGroupErrorsParent( + MEPBase, TestMutuallyDependenceGroupErrors): + pass + + class TestMutuallyExclusiveSimpleParent( MEPBase, TestMutuallyExclusiveSimple): pass @@ -2861,7 +3226,7 @@ subparsers = parser.add_subparsers() for subparser_sig in subparsers_sigs: subparsers.add_parser(*subparser_sig.args, - **subparser_sig.kwargs) + **subparser_sig.kwargs) return parser def _test(self, tester, parser_text): @@ -2957,9 +3322,9 @@ env.set("COLUMNS", '15') self.addCleanup(env.__exit__) - parser_signature = TestHelpBiggerOptionals.parser_signature - argument_signatures = TestHelpBiggerOptionals.argument_signatures - argument_group_signatures = TestHelpBiggerOptionals.argument_group_signatures + parser_signature = TestHelpBiggerOptionals.parser_signature + argument_signatures = TestHelpBiggerOptionals.argument_signatures + argument_group_signatures = TestHelpBiggerOptionals.argument_group_signatures usage = '''\ usage: PROG [-h] @@ -2998,7 +3363,7 @@ EPILOG ''' - version = TestHelpBiggerOptionals.version + version = TestHelpBiggerOptionals.version class TestHelpBiggerOptionalGroups(HelpTestCase): @@ -3133,7 +3498,7 @@ class TestHelpWrappingShortNames(HelpTestCase): """Make sure that text after short names starts on the first line""" - parser_signature = Sig(prog='PROG', description= 'D\nD' * 30) + parser_signature = Sig(prog='PROG', description='D\nD' * 30) argument_signatures = [ Sig('-x', metavar='XX', help='XHH HX' * 20), Sig('y', metavar='yyy', help='YH YH' * 20), @@ -3994,7 +4359,8 @@ """Test the default help for the version action""" parser_signature = Sig(prog='PROG', description='description') - argument_signatures = [Sig('-V', '--version', action='version', version='3.6')] + argument_signatures = [ + Sig('-V', '--version', action='version', version='3.6')] argument_group_signatures = [] usage = '''\ usage: PROG [-h] [-V]