@@ -2253,6 +2253,95 @@ class TestNegativeNumber(ParserTestCase):
2253
2253
('--complex -1e-3j' , NS (int = None , float = None , complex = - 0.001j )),
2254
2254
]
2255
2255
2256
+ class TestArgumentAndSubparserSuggestions (TestCase ):
2257
+ """Test error handling and suggestion when a user makes a typo"""
2258
+
2259
+ def test_wrong_argument_error_with_suggestions (self ):
2260
+ parser = ErrorRaisingArgumentParser (suggest_on_error = True )
2261
+ parser .add_argument ('foo' , choices = ['bar' , 'baz' ])
2262
+ with self .assertRaises (ArgumentParserError ) as excinfo :
2263
+ parser .parse_args (('bazz' ,))
2264
+ self .assertIn (
2265
+ "error: argument foo: invalid choice: 'bazz', maybe you meant 'baz'? (choose from bar, baz)" ,
2266
+ excinfo .exception .stderr
2267
+ )
2268
+
2269
+ def test_wrong_argument_error_no_suggestions (self ):
2270
+ parser = ErrorRaisingArgumentParser (suggest_on_error = False )
2271
+ parser .add_argument ('foo' , choices = ['bar' , 'baz' ])
2272
+ with self .assertRaises (ArgumentParserError ) as excinfo :
2273
+ parser .parse_args (('bazz' ,))
2274
+ self .assertIn (
2275
+ "error: argument foo: invalid choice: 'bazz' (choose from bar, baz)" ,
2276
+ excinfo .exception .stderr ,
2277
+ )
2278
+
2279
+ def test_wrong_argument_subparsers_with_suggestions (self ):
2280
+ parser = ErrorRaisingArgumentParser (suggest_on_error = True )
2281
+ subparsers = parser .add_subparsers (required = True )
2282
+ subparsers .add_parser ('foo' )
2283
+ subparsers .add_parser ('bar' )
2284
+ with self .assertRaises (ArgumentParserError ) as excinfo :
2285
+ parser .parse_args (('baz' ,))
2286
+ self .assertIn (
2287
+ "error: argument {foo,bar}: invalid choice: 'baz', maybe you meant"
2288
+ " 'bar'? (choose from foo, bar)" ,
2289
+ excinfo .exception .stderr ,
2290
+ )
2291
+
2292
+ def test_wrong_argument_subparsers_no_suggestions (self ):
2293
+ parser = ErrorRaisingArgumentParser (suggest_on_error = False )
2294
+ subparsers = parser .add_subparsers (required = True )
2295
+ subparsers .add_parser ('foo' )
2296
+ subparsers .add_parser ('bar' )
2297
+ with self .assertRaises (ArgumentParserError ) as excinfo :
2298
+ parser .parse_args (('baz' ,))
2299
+ self .assertIn (
2300
+ "error: argument {foo,bar}: invalid choice: 'baz' (choose from foo, bar)" ,
2301
+ excinfo .exception .stderr ,
2302
+ )
2303
+
2304
+ def test_wrong_argument_no_suggestion_implicit (self ):
2305
+ parser = ErrorRaisingArgumentParser ()
2306
+ parser .add_argument ('foo' , choices = ['bar' , 'baz' ])
2307
+ with self .assertRaises (ArgumentParserError ) as excinfo :
2308
+ parser .parse_args (('bazz' ,))
2309
+ self .assertIn (
2310
+ "error: argument foo: invalid choice: 'bazz' (choose from bar, baz)" ,
2311
+ excinfo .exception .stderr ,
2312
+ )
2313
+
2314
+ def test_suggestions_choices_empty (self ):
2315
+ parser = ErrorRaisingArgumentParser (suggest_on_error = True )
2316
+ parser .add_argument ('foo' , choices = [])
2317
+ with self .assertRaises (ArgumentParserError ) as excinfo :
2318
+ parser .parse_args (('bazz' ,))
2319
+ self .assertIn (
2320
+ "error: argument foo: invalid choice: 'bazz' (choose from )" ,
2321
+ excinfo .exception .stderr ,
2322
+ )
2323
+
2324
+ def test_suggestions_choices_int (self ):
2325
+ parser = ErrorRaisingArgumentParser (suggest_on_error = True )
2326
+ parser .add_argument ('foo' , choices = [1 , 2 ])
2327
+ with self .assertRaises (ArgumentParserError ) as excinfo :
2328
+ parser .parse_args (('3' ,))
2329
+ self .assertIn (
2330
+ "error: argument foo: invalid choice: '3' (choose from 1, 2)" ,
2331
+ excinfo .exception .stderr ,
2332
+ )
2333
+
2334
+ def test_suggestions_choices_mixed_types (self ):
2335
+ parser = ErrorRaisingArgumentParser (suggest_on_error = True )
2336
+ parser .add_argument ('foo' , choices = [1 , '2' ])
2337
+ with self .assertRaises (ArgumentParserError ) as excinfo :
2338
+ parser .parse_args (('3' ,))
2339
+ self .assertIn (
2340
+ "error: argument foo: invalid choice: '3' (choose from 1, 2)" ,
2341
+ excinfo .exception .stderr ,
2342
+ )
2343
+
2344
+
2256
2345
class TestInvalidAction (TestCase ):
2257
2346
"""Test invalid user defined Action"""
2258
2347
@@ -2505,18 +2594,6 @@ def test_required_subparsers_no_destination_error(self):
2505
2594
'error: the following arguments are required: {foo,bar}\n $'
2506
2595
)
2507
2596
2508
- def test_wrong_argument_subparsers_no_destination_error (self ):
2509
- parser = ErrorRaisingArgumentParser ()
2510
- subparsers = parser .add_subparsers (required = True )
2511
- subparsers .add_parser ('foo' )
2512
- subparsers .add_parser ('bar' )
2513
- with self .assertRaises (ArgumentParserError ) as excinfo :
2514
- parser .parse_args (('baz' ,))
2515
- self .assertRegex (
2516
- excinfo .exception .stderr ,
2517
- r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from foo, bar\)\n$"
2518
- )
2519
-
2520
2597
def test_optional_subparsers (self ):
2521
2598
parser = ErrorRaisingArgumentParser ()
2522
2599
subparsers = parser .add_subparsers (dest = 'command' , required = False )
@@ -2862,7 +2939,7 @@ def test_single_parent_mutex(self):
2862
2939
parser = ErrorRaisingArgumentParser (parents = [self .ab_mutex_parent ])
2863
2940
self ._test_mutex_ab (parser .parse_args )
2864
2941
2865
- def test_single_granparent_mutex (self ):
2942
+ def test_single_grandparent_mutex (self ):
2866
2943
parents = [self .ab_mutex_parent ]
2867
2944
parser = ErrorRaisingArgumentParser (add_help = False , parents = parents )
2868
2945
parser = ErrorRaisingArgumentParser (parents = [parser ])
0 commit comments