⚡ Sangsakala Proxy 🏠 Home
Skip to content

gh-161282: Fix quadratic time in optparse when parsing many positional arguments - #161283

Open
thejesh23 wants to merge 2 commits into
python:mainfrom
thejesh23:optparse-positionals
Open

thejesh23 wants to merge 2 commits into
python:mainfrom
thejesh23:optparse-positionals

Conversation

@thejesh23

@thejesh23 thejesh23 commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

OptionParser._process_args() removed every positional argument from the front of rargs with del rargs[0], so parsing N positional arguments took O(N²) time. With 200,000 positional arguments, parse_args() goes from 2.47 s to 8 ms.

The fix appends each run of consecutive positional arguments to largs and deletes the run from rargs in one step. A run stops at the next argument that is handled as an option (arg[:1] == "-" and len(arg) > 1, which includes --), so option processing, -- and callbacks are unchanged, and callbacks still see the same parser.largs and parser.rargs. Options are still removed one at a time, because callbacks may inspect and modify parser.rargs.

positional args main this PR
25,000 33.2 ms 1.0 ms
50,000 150.2 ms 1.9 ms
100,000 616.4 ms 4.1 ms
200,000 2467.2 ms 8.2 ms

Short command lines are unaffected: about 1.5 µs per parse_args() call before and after, within ±3%.

Testing:

  • New tests cover runs of positional arguments mixed with options, -, empty strings and --, and callbacks that consume or modify largs and rargs between runs.
  • I compared the old and new code on 200,000 random argument lists. The lists used count, append and nargs=2 options, callbacks that read or modify largs and rargs, --, -, empty strings, unknown options, and disable_interspersed_args(). The parsed values, leftover arguments, what the callbacks saw, and the errors were all identical.
  • test_optparse, test_argparse, test_getopt and the full test suite pass.

AI disclosure: prepared with the help of Claude Code; I reviewed the change and the test results.

Each positional argument was removed from the front of the remaining
argument list with 'del rargs[0]', so parsing N positional arguments
took O(N**2) time.  Move each run of consecutive positional arguments
to 'largs' and delete it from 'rargs' in one step.  Options and
callbacks still see the same 'parser.largs' and 'parser.rargs'.
@thejesh23

Copy link
Copy Markdown
Contributor Author

The ASan failure is test_profiling (test_sampling_with_collapsed_export, ':' not found in '<unreadable frame>'), the known flake tracked in gh-160334; it's unrelated to this change. test_optparse and the rest of the suite passed in that job.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant