Skip to content

Commit f113ee3

Browse files
Add argparse benchmarks for subparsers and many optionals (#367)
* 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 :)
1 parent ebc5013 commit f113ee3

File tree

4 files changed

+147
-0
lines changed

4 files changed

+147
-0
lines changed

pyperformance/data-files/benchmarks/MANIFEST

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
name metafile
44
2to3 <local>
5+
argparse <local>
6+
argparse_subparsers <local:argparse>
57
async_generators <local>
68
async_tree <local>
79
async_tree_cpu_io_mixed <local:async_tree>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[project]
2+
name = "pyperformance_bm_argparse"
3+
requires-python = ">=3.8"
4+
dependencies = ["pyperf"]
5+
urls = {repository = "https://github.com/python/pyperformance"}
6+
dynamic = ["version"]
7+
8+
[tool.pyperformance]
9+
name = "argparse_subparsers"
10+
extra_opts = ["subparsers"]
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[project]
2+
name = "pyperformance_bm_argparse"
3+
requires-python = ">=3.8"
4+
dependencies = ["pyperf"]
5+
urls = {repository = "https://github.com/python/pyperformance"}
6+
dynamic = ["version"]
7+
8+
[tool.pyperformance]
9+
name = "argparse_many_optionals"
10+
extra_opts = ["many_optionals"]
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
"""
2+
Benchmark argparse programs with:
3+
1) multiple subparsers, each with their own subcommands, and then parse a series of command-line arguments.
4+
2) a large number of optional arguments, and then parse a series of command-line arguments.
5+
6+
Author: Savannah Ostrowski
7+
"""
8+
9+
import argparse
10+
import pyperf
11+
12+
13+
def generate_arguments(i: int) -> list:
14+
arguments = ["input.txt", "output.txt"]
15+
for i in range(i):
16+
arguments.extend([f"--option{i}", f"value{i}"])
17+
return arguments
18+
19+
20+
def bm_many_optionals() -> argparse.ArgumentParser:
21+
parser = argparse.ArgumentParser(description="A version control system CLI")
22+
23+
parser.add_argument("--version", action="version", version="1.0")
24+
25+
subparsers = parser.add_subparsers(dest="command", required=True)
26+
27+
add_parser = subparsers.add_parser("add", help="Add a file to the repository")
28+
add_parser.add_argument("files", nargs="+", help="List of files to add to staging")
29+
30+
commit_parser = subparsers.add_parser(
31+
"commit", help="Commit changes to the repository"
32+
)
33+
commit_parser.add_argument("-m", "--message", required=True, help="Commit message")
34+
35+
commit_group = commit_parser.add_mutually_exclusive_group(required=False)
36+
commit_group.add_argument(
37+
"--amend", action="store_true", help="Amend the last commit"
38+
)
39+
commit_group.add_argument(
40+
"--no-edit", action="store_true", help="Reuse the last commit message"
41+
)
42+
43+
push_parser = subparsers.add_parser(
44+
"push", help="Push changes to remote repository"
45+
)
46+
47+
network_group = push_parser.add_argument_group("Network options")
48+
network_group.add_argument("--dryrun", action="store_true", help="Simulate changes")
49+
network_group.add_argument(
50+
"--timeout", type=int, default=30, help="Timeout in seconds"
51+
)
52+
53+
auth_group = push_parser.add_argument_group("Authentication options")
54+
auth_group.add_argument(
55+
"--username", required=True, help="Username for authentication"
56+
)
57+
auth_group.add_argument(
58+
"--password", required=True, help="Password for authentication"
59+
)
60+
61+
global_group = parser.add_mutually_exclusive_group()
62+
global_group.add_argument("--verbose", action="store_true", help="Verbose output")
63+
global_group.add_argument("--quiet", action="store_true", help="Quiet output")
64+
65+
argument_lists = [
66+
["--verbose", "add", "file1.txt", "file2.txt"],
67+
["add", "file1.txt", "file2.txt"],
68+
["commit", "-m", "Initial commit"],
69+
["commit", "-m", "Add new feature", "--amend"],
70+
[
71+
"push",
72+
"--dryrun",
73+
"--timeout",
74+
"60",
75+
"--username",
76+
"user",
77+
"--password",
78+
"pass",
79+
],
80+
]
81+
82+
for arguments in argument_lists:
83+
parser.parse_args(arguments)
84+
85+
86+
def bm_subparsers() -> argparse.ArgumentParser:
87+
parser = argparse.ArgumentParser()
88+
89+
parser.add_argument("input_file", type=str, help="The input file")
90+
parser.add_argument("output_file", type=str, help="The output file")
91+
92+
for i in range(1000):
93+
parser.add_argument(f"--option{i}", type=str, help=f"Optional argument {i}")
94+
95+
argument_lists = [
96+
generate_arguments(500),
97+
generate_arguments(1000),
98+
]
99+
100+
for args in argument_lists:
101+
parser.parse_args(args)
102+
103+
104+
BENCHMARKS = {
105+
"many_optionals": bm_many_optionals,
106+
"subparsers": bm_subparsers,
107+
}
108+
109+
110+
def add_cmdline_args(cmd, args):
111+
cmd.append(args.benchmark)
112+
113+
114+
def add_parser_args(parser):
115+
parser.add_argument("benchmark", choices=BENCHMARKS, help="Which benchmark to run.")
116+
117+
118+
if __name__ == "__main__":
119+
runner = pyperf.Runner(add_cmdline_args=add_cmdline_args)
120+
runner.metadata["description"] = "Argparse benchmark"
121+
add_parser_args(runner.argparser)
122+
args = runner.parse_args()
123+
benchmark = args.benchmark
124+
125+
runner.bench_func(args.benchmark, BENCHMARKS[args.benchmark])

0 commit comments

Comments
 (0)