Commit ec14116
committed
gh-53584: Prevent variable-nargs options from stealing required positional args
Options with nargs='?', nargs='*', or nargs='+' were greedily consuming
argument strings that should have been reserved for required positional
arguments. For example:
parser.add_argument('--foo', nargs='?')
parser.add_argument('bar')
parser.parse_args(['--foo', 'abc']) # bar got nothing
argparse works by pattern-matching, with the bulk of its logic defined
in _parse_known_args(). That method encodes each argument string as a
single character ('O' for a recognised option flag, 'A' for everything
else, and '-' for strings following '--') which gives us a resulting
string pattern (e.g. 'OAOA'). We then "consume" arguments using this
string pattern, handling both positionals (via the consume_positionals()
closure) and optionals (via consume_optional()).
The bug arises in the latter. consume_optional() processes options by
building a regex based on the option's nargs (e.g. '-*A?-*' for
nargs='?') and then runs this regex against the remainder of the string
pattern (i.e. anything following the option flag). This is done via
_match_argument(). The regex will always stop at the next option flag
('O' token) but for non-fixed nargs values like '?' and '+' may greedily
consume every positional ('A' token) up to that point.
This fix works by manipulating the string pattern as part of our
optional consumption. Any 'A' tokens that are required by remaining
positionals are masked to 'O' to prevent the regex consuming them.
Masking will only consider tokens up to the next option flag ('O') and
it both accounts for what future options can absorb (to avoid masking
more than is necessary) and ensures that at least the minimum arguments
required for the optional are actually consumed.
In addition, we also handle the parse_intermixed_args() case. In
intermixed mode, positional-typed arguments already collected to the
left of the current option are also accounted for, since they will
satisfy positionals in the second-pass parse.
Signed-off-by: Stephen Finucane <stephen@that.guru>1 parent c2c4dfa commit ec14116
File tree
3 files changed
+96
-7
lines changed- Lib
- test
- Misc/NEWS.d/next/Library
3 files changed
+96
-7
lines changed| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2199 | 2199 | | |
2200 | 2200 | | |
2201 | 2201 | | |
| 2202 | + | |
| 2203 | + | |
| 2204 | + | |
| 2205 | + | |
| 2206 | + | |
| 2207 | + | |
| 2208 | + | |
| 2209 | + | |
| 2210 | + | |
| 2211 | + | |
| 2212 | + | |
2202 | 2213 | | |
2203 | 2214 | | |
2204 | 2215 | | |
| |||
2282 | 2293 | | |
2283 | 2294 | | |
2284 | 2295 | | |
| 2296 | + | |
| 2297 | + | |
| 2298 | + | |
| 2299 | + | |
| 2300 | + | |
| 2301 | + | |
| 2302 | + | |
| 2303 | + | |
| 2304 | + | |
| 2305 | + | |
| 2306 | + | |
| 2307 | + | |
| 2308 | + | |
| 2309 | + | |
| 2310 | + | |
| 2311 | + | |
| 2312 | + | |
| 2313 | + | |
| 2314 | + | |
| 2315 | + | |
| 2316 | + | |
| 2317 | + | |
| 2318 | + | |
| 2319 | + | |
| 2320 | + | |
| 2321 | + | |
| 2322 | + | |
| 2323 | + | |
| 2324 | + | |
| 2325 | + | |
| 2326 | + | |
| 2327 | + | |
| 2328 | + | |
| 2329 | + | |
| 2330 | + | |
| 2331 | + | |
| 2332 | + | |
| 2333 | + | |
| 2334 | + | |
| 2335 | + | |
| 2336 | + | |
| 2337 | + | |
| 2338 | + | |
| 2339 | + | |
| 2340 | + | |
| 2341 | + | |
| 2342 | + | |
| 2343 | + | |
| 2344 | + | |
| 2345 | + | |
| 2346 | + | |
| 2347 | + | |
| 2348 | + | |
| 2349 | + | |
| 2350 | + | |
| 2351 | + | |
| 2352 | + | |
| 2353 | + | |
| 2354 | + | |
| 2355 | + | |
| 2356 | + | |
| 2357 | + | |
| 2358 | + | |
| 2359 | + | |
| 2360 | + | |
| 2361 | + | |
| 2362 | + | |
| 2363 | + | |
| 2364 | + | |
| 2365 | + | |
| 2366 | + | |
| 2367 | + | |
| 2368 | + | |
| 2369 | + | |
| 2370 | + | |
| 2371 | + | |
| 2372 | + | |
| 2373 | + | |
| 2374 | + | |
| 2375 | + | |
| 2376 | + | |
| 2377 | + | |
2285 | 2378 | | |
2286 | 2379 | | |
2287 | 2380 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
698 | 698 | | |
699 | 699 | | |
700 | 700 | | |
701 | | - | |
702 | 701 | | |
703 | 702 | | |
704 | 703 | | |
| |||
708 | 707 | | |
709 | 708 | | |
710 | 709 | | |
711 | | - | |
712 | 710 | | |
713 | 711 | | |
714 | 712 | | |
| |||
720 | 718 | | |
721 | 719 | | |
722 | 720 | | |
723 | | - | |
724 | 721 | | |
725 | 722 | | |
726 | 723 | | |
| |||
762 | 759 | | |
763 | 760 | | |
764 | 761 | | |
765 | | - | |
766 | 762 | | |
767 | 763 | | |
768 | 764 | | |
| |||
789 | 785 | | |
790 | 786 | | |
791 | 787 | | |
792 | | - | |
793 | 788 | | |
794 | 789 | | |
795 | 790 | | |
| |||
799 | 794 | | |
800 | 795 | | |
801 | 796 | | |
802 | | - | |
803 | 797 | | |
804 | 798 | | |
805 | 799 | | |
| |||
6849 | 6843 | | |
6850 | 6844 | | |
6851 | 6845 | | |
6852 | | - | |
6853 | 6846 | | |
6854 | 6847 | | |
6855 | 6848 | | |
| |||
Lines changed: 3 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
0 commit comments