Skip to content

Commit

Permalink
Add argparse benchmarks for subparsers and many optionals (#367)
Browse files Browse the repository at this point in the history
* Add argparse benchmark

* Add benchmark for testing lots of args

* Reorder in MANIFEST

* Fix formatting

* Add newline

* Formatting

* Update description

* Formatting...again

* Update docstring

* Attempting to fix the tests

* Remove line

* Refactor into single run_benchmark

* Add newline;

* Remove extraneous files

* Formatting :)
  • Loading branch information
savannahostrowski authored Nov 15, 2024
1 parent ebc5013 commit f113ee3
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 0 deletions.
2 changes: 2 additions & 0 deletions pyperformance/data-files/benchmarks/MANIFEST
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

name metafile
2to3 <local>
argparse <local>
argparse_subparsers <local:argparse>
async_generators <local>
async_tree <local>
async_tree_cpu_io_mixed <local:async_tree>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[project]
name = "pyperformance_bm_argparse"
requires-python = ">=3.8"
dependencies = ["pyperf"]
urls = {repository = "https://github.com/python/pyperformance"}
dynamic = ["version"]

[tool.pyperformance]
name = "argparse_subparsers"
extra_opts = ["subparsers"]
10 changes: 10 additions & 0 deletions pyperformance/data-files/benchmarks/bm_argparse/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[project]
name = "pyperformance_bm_argparse"
requires-python = ">=3.8"
dependencies = ["pyperf"]
urls = {repository = "https://github.com/python/pyperformance"}
dynamic = ["version"]

[tool.pyperformance]
name = "argparse_many_optionals"
extra_opts = ["many_optionals"]
125 changes: 125 additions & 0 deletions pyperformance/data-files/benchmarks/bm_argparse/run_benchmark.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
"""
Benchmark argparse programs with:
1) multiple subparsers, each with their own subcommands, and then parse a series of command-line arguments.
2) a large number of optional arguments, and then parse a series of command-line arguments.
Author: Savannah Ostrowski
"""

import argparse
import pyperf


def generate_arguments(i: int) -> list:
arguments = ["input.txt", "output.txt"]
for i in range(i):
arguments.extend([f"--option{i}", f"value{i}"])
return arguments


def bm_many_optionals() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="A version control system CLI")

parser.add_argument("--version", action="version", version="1.0")

subparsers = parser.add_subparsers(dest="command", required=True)

add_parser = subparsers.add_parser("add", help="Add a file to the repository")
add_parser.add_argument("files", nargs="+", help="List of files to add to staging")

commit_parser = subparsers.add_parser(
"commit", help="Commit changes to the repository"
)
commit_parser.add_argument("-m", "--message", required=True, help="Commit message")

commit_group = commit_parser.add_mutually_exclusive_group(required=False)
commit_group.add_argument(
"--amend", action="store_true", help="Amend the last commit"
)
commit_group.add_argument(
"--no-edit", action="store_true", help="Reuse the last commit message"
)

push_parser = subparsers.add_parser(
"push", help="Push changes to remote repository"
)

network_group = push_parser.add_argument_group("Network options")
network_group.add_argument("--dryrun", action="store_true", help="Simulate changes")
network_group.add_argument(
"--timeout", type=int, default=30, help="Timeout in seconds"
)

auth_group = push_parser.add_argument_group("Authentication options")
auth_group.add_argument(
"--username", required=True, help="Username for authentication"
)
auth_group.add_argument(
"--password", required=True, help="Password for authentication"
)

global_group = parser.add_mutually_exclusive_group()
global_group.add_argument("--verbose", action="store_true", help="Verbose output")
global_group.add_argument("--quiet", action="store_true", help="Quiet output")

argument_lists = [
["--verbose", "add", "file1.txt", "file2.txt"],
["add", "file1.txt", "file2.txt"],
["commit", "-m", "Initial commit"],
["commit", "-m", "Add new feature", "--amend"],
[
"push",
"--dryrun",
"--timeout",
"60",
"--username",
"user",
"--password",
"pass",
],
]

for arguments in argument_lists:
parser.parse_args(arguments)


def bm_subparsers() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser()

parser.add_argument("input_file", type=str, help="The input file")
parser.add_argument("output_file", type=str, help="The output file")

for i in range(1000):
parser.add_argument(f"--option{i}", type=str, help=f"Optional argument {i}")

argument_lists = [
generate_arguments(500),
generate_arguments(1000),
]

for args in argument_lists:
parser.parse_args(args)


BENCHMARKS = {
"many_optionals": bm_many_optionals,
"subparsers": bm_subparsers,
}


def add_cmdline_args(cmd, args):
cmd.append(args.benchmark)


def add_parser_args(parser):
parser.add_argument("benchmark", choices=BENCHMARKS, help="Which benchmark to run.")


if __name__ == "__main__":
runner = pyperf.Runner(add_cmdline_args=add_cmdline_args)
runner.metadata["description"] = "Argparse benchmark"
add_parser_args(runner.argparser)
args = runner.parse_args()
benchmark = args.benchmark

runner.bench_func(args.benchmark, BENCHMARKS[args.benchmark])

0 comments on commit f113ee3

Please sign in to comment.