@@ -664,6 +664,17 @@ class TestOptionalsNargs3(ParserTestCase):
664664 ('-x a b c' , NS (x = ['a' , 'b' , 'c' ])),
665665 ]
666666
667+ def test_does_not_steal_required_positional (self ):
668+ # https://github.com/python/cpython/issues/53584
669+ # Fixed integer nargs is never greedy: --foo takes exactly N args and
670+ # leaves the remainder for positionals.
671+ parser = ErrorRaisingArgumentParser ()
672+ parser .add_argument ('--foo' , nargs = 2 )
673+ parser .add_argument ('bar' )
674+ args = parser .parse_args (['--foo' , 'a' , 'b' , 'c' ])
675+ self .assertEqual (args .foo , ['a' , 'b' ])
676+ self .assertEqual (args .bar , 'c' )
677+
667678
668679class TestOptionalsNargsOptional (ParserTestCase ):
669680 """Tests specifying an Optional arg for an Optional"""
@@ -687,6 +698,51 @@ class TestOptionalsNargsOptional(ParserTestCase):
687698 ('-z 2' , NS (w = None , x = None , y = 'spam' , z = 2 )),
688699 ]
689700
701+ @unittest .expectedFailure
702+ def test_does_not_steal_required_positional (self ):
703+ # https://github.com/python/cpython/issues/53584
704+ parser = ErrorRaisingArgumentParser ()
705+ parser .add_argument ('--foo' , nargs = '?' )
706+ parser .add_argument ('bar' )
707+ args = parser .parse_args (['--foo' , 'abc' ])
708+ self .assertIsNone (args .foo )
709+ self .assertEqual (args .bar , 'abc' )
710+
711+ @unittest .expectedFailure
712+ def test_does_not_steal_two_required_positionals (self ):
713+ # https://github.com/python/cpython/issues/53584
714+ parser = ErrorRaisingArgumentParser ()
715+ parser .add_argument ('--foo' , nargs = '?' )
716+ parser .add_argument ('bar' )
717+ parser .add_argument ('bax' )
718+ args = parser .parse_args (['--foo' , 'a' , 'b' ])
719+ self .assertIsNone (args .foo )
720+ self .assertEqual (args .bar , 'a' )
721+ self .assertEqual (args .bax , 'b' )
722+
723+ @unittest .expectedFailure
724+ def test_does_not_steal_two_required_positional_interspersed (self ):
725+ # https://github.com/python/cpython/issues/53584
726+ parser = ErrorRaisingArgumentParser ()
727+ parser .add_argument ('--foo' , nargs = '?' )
728+ parser .add_argument ('--bar' , nargs = '?' )
729+ parser .add_argument ('baz' )
730+ parser .add_argument ('bax' )
731+ args = parser .parse_args (['--foo' , 'a' , '--bar' , 'b' ])
732+ self .assertEqual (args .baz , 'a' )
733+ self .assertEqual (args .bax , 'b' )
734+
735+ def test_greedy_when_positional_also_optional (self ):
736+ # https://github.com/python/cpython/issues/53584
737+ # When the following positional is also optional, --foo taking the arg
738+ # is acceptable (both are optional, no unambiguous correct answer).
739+ parser = ErrorRaisingArgumentParser ()
740+ parser .add_argument ('--foo' , nargs = '?' )
741+ parser .add_argument ('bar' , nargs = '?' )
742+ args = parser .parse_args (['--foo' , 'abc' ])
743+ self .assertEqual (args .foo , 'abc' )
744+ self .assertIsNone (args .bar )
745+
690746
691747class TestOptionalsNargsZeroOrMore (ParserTestCase ):
692748 """Tests specifying args for an Optional that accepts zero or more"""
@@ -706,6 +762,16 @@ class TestOptionalsNargsZeroOrMore(ParserTestCase):
706762 ('-y a b' , NS (x = None , y = ['a' , 'b' ])),
707763 ]
708764
765+ @unittest .expectedFailure
766+ def test_does_not_steal_required_positional (self ):
767+ # https://github.com/python/cpython/issues/53584
768+ parser = ErrorRaisingArgumentParser ()
769+ parser .add_argument ('--foo' , nargs = '*' )
770+ parser .add_argument ('bar' )
771+ args = parser .parse_args (['--foo' , 'abc' ])
772+ self .assertEqual (args .foo , [])
773+ self .assertEqual (args .bar , 'abc' )
774+
709775
710776class TestOptionalsNargsOneOrMore (ParserTestCase ):
711777 """Tests specifying args for an Optional that accepts one or more"""
@@ -723,6 +789,29 @@ class TestOptionalsNargsOneOrMore(ParserTestCase):
723789 ('-y a b' , NS (x = None , y = ['a' , 'b' ])),
724790 ]
725791
792+ @unittest .expectedFailure
793+ def test_does_not_steal_required_positional (self ):
794+ # https://github.com/python/cpython/issues/53584
795+ parser = ErrorRaisingArgumentParser ()
796+ parser .add_argument ('--foo' , nargs = '+' )
797+ parser .add_argument ('bar' )
798+ args = parser .parse_args (['--foo' , 'a' , 'b' ])
799+ self .assertEqual (args .foo , ['a' ])
800+ self .assertEqual (args .bar , 'b' )
801+
802+ @unittest .expectedFailure
803+ def test_does_not_steal_interspersed_required_positional (self ):
804+ # https://github.com/python/cpython/issues/53584
805+ parser = ErrorRaisingArgumentParser ()
806+ parser .add_argument ('--foo' , nargs = '+' )
807+ parser .add_argument ('--bar' , nargs = '+' )
808+ parser .add_argument ('baz' )
809+ parser .add_argument ('bax' )
810+ args = parser .parse_args (['--foo' , 'a' , 'c' , '--bar' , 'b' , 'd' ])
811+ self .assertEqual (args .foo , ['a' ])
812+ self .assertEqual (args .bar , ['b' ])
813+ self .assertEqual (args .baz , 'c' )
814+ self .assertEqual (args .bax , 'd' )
726815
727816class TestOptionalsChoices (ParserTestCase ):
728817 """Tests specifying the choices for an Optional"""
@@ -6760,6 +6849,25 @@ def test_invalid_args(self):
67606849 parser = ErrorRaisingArgumentParser (prog = 'PROG' )
67616850 self .assertRaises (ArgumentParserError , parser .parse_intermixed_args , ['a' ])
67626851
6852+ @unittest .expectedFailure
6853+ def test_variable_nargs_option_before_positional (self ):
6854+ # https://github.com/python/cpython/issues/53584
6855+ parser = ErrorRaisingArgumentParser ()
6856+ parser .add_argument ('--foo' , nargs = '?' )
6857+ parser .add_argument ('bar' )
6858+ args = parser .parse_intermixed_args (['--foo' , 'abc' ])
6859+ self .assertIsNone (args .foo )
6860+ self .assertEqual (args .bar , 'abc' )
6861+
6862+ def test_variable_nargs_option_after_positional (self ):
6863+ # https://github.com/python/cpython/issues/53584
6864+ parser = ErrorRaisingArgumentParser ()
6865+ parser .add_argument ('--foo' , nargs = '?' )
6866+ parser .add_argument ('bar' )
6867+ args = parser .parse_intermixed_args (['abc' , '--foo' , 'xyz' ])
6868+ self .assertEqual (args .foo , 'xyz' )
6869+ self .assertEqual (args .bar , 'abc' )
6870+
67636871
67646872class TestIntermixedMessageContentError (TestCase ):
67656873 # case where Intermixed gives different error message
0 commit comments