|
1 | 1 | import re |
2 | | -import json |
3 | 2 |
|
4 | | -output = """ |
5 | | -usage: qsiprep [-h] [--skip-bids-validation] |
6 | | - [--output-resolution RESOLUTION] |
7 | | - [--participant-label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...]] |
8 | | - |
9 | | -Options for workflow: |
10 | | - --output-resolution {1.2,2,3} |
11 | | - Output resolution. (default: 1.25) |
12 | | - --participant-label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...] |
13 | | - One or more participant identifiers. |
14 | | -
|
15 | | -Options for filtering BIDS queries: |
16 | | - --skip-bids-validation |
17 | | - Skip BIDS validation. |
18 | | -""" |
19 | 3 |
|
20 | | - |
21 | | -def parse(output): |
22 | | - parts = re.split(r"\n(?=[A-Z][^:]+:)", output) |
| 4 | +def parse_help_sections(help_output: str): |
| 5 | + parts = re.split(r"\n(?=[A-Z][^:]+:)", help_output) |
23 | 6 | sections = [] |
| 7 | + |
24 | 8 | for part in parts: |
25 | 9 | lines = part.strip().split("\n") |
26 | 10 | if not lines: |
27 | 11 | continue |
| 12 | + |
28 | 13 | header = lines[0].strip().rstrip(":") |
29 | 14 | if "usage" in header.lower(): |
30 | 15 | continue |
| 16 | + |
31 | 17 | content = "\n".join(lines[1:]) |
32 | 18 | if "--" not in content: |
33 | 19 | continue |
34 | 20 |
|
35 | 21 | options = [] |
36 | | - # Fix: Better splitting of argument blocks |
37 | 22 | arg_blocks = re.split(r"\n\s+(?=--)", "\n " + content) |
38 | | - |
39 | 23 | for block in arg_blocks: |
40 | 24 | flag_match = re.search(r"(--[a-zA-Z0-9-]+)", block) |
41 | 25 | if not flag_match: |
42 | 26 | continue |
43 | | - flag = flag_match.group(1) |
44 | 27 |
|
45 | | - choice_match = re.search(r"\{([^}]+)\}", block) |
46 | | - if choice_match: |
47 | | - [c.strip() for c in choice_match.group(1).split(",")] |
48 | | - |
49 | | - # IMPROVED: Clean up description parsing |
50 | | - # The description usually starts after the flag/metavar block |
51 | | - # In argparse, it's often separated by multiple spaces or a newline+indent |
52 | | - |
53 | | - # Find the first line after the flag line |
| 28 | + flag = flag_match.group(1) |
54 | 29 | block_lines = block.split("\n") |
55 | | - if len(block_lines) > 1: |
56 | | - description = " ".join([line.strip() for line in block_lines[1:]]) |
57 | | - else: |
58 | | - description = "" |
59 | | - |
60 | | - description = re.sub(r"\s+", " ", description) |
61 | | - |
| 30 | + description = " ".join(line.strip() for line in block_lines[1:]) |
| 31 | + description = re.sub(r"\s+", " ", description).strip() |
62 | 32 | options.append({"flag": flag, "description": description}) |
| 33 | + |
63 | 34 | if options: |
64 | 35 | sections.append({"title": header, "options": options}) |
| 36 | + |
65 | 37 | return sections |
66 | 38 |
|
67 | 39 |
|
68 | | -print(json.dumps(parse(output), indent=2)) |
| 40 | +def test_parse_help_sections_extracts_flags_and_descriptions(): |
| 41 | + output = """ |
| 42 | +usage: qsiprep [-h] [--skip-bids-validation] |
| 43 | + [--output-resolution RESOLUTION] |
| 44 | +
|
| 45 | +Options for workflow: |
| 46 | + --output-resolution {1.2,2,3} |
| 47 | + Output resolution. (default: 1.25) |
| 48 | + --participant-label PARTICIPANT_LABEL [PARTICIPANT_LABEL ...] |
| 49 | + One or more participant identifiers. |
| 50 | +
|
| 51 | +Options for filtering BIDS queries: |
| 52 | + --skip-bids-validation |
| 53 | + Skip BIDS validation. |
| 54 | +""" |
| 55 | + |
| 56 | + sections = parse_help_sections(output) |
| 57 | + |
| 58 | + assert [s["title"] for s in sections] == [ |
| 59 | + "Options for workflow", |
| 60 | + "Options for filtering BIDS queries", |
| 61 | + ] |
| 62 | + assert sections[0]["options"][0]["flag"] == "--output-resolution" |
| 63 | + assert "Output resolution" in sections[0]["options"][0]["description"] |
| 64 | + assert sections[1]["options"][0]["flag"] == "--skip-bids-validation" |
| 65 | + |
| 66 | + |
| 67 | +def test_parse_help_sections_ignores_text_without_flags(): |
| 68 | + output = """ |
| 69 | +Description: |
| 70 | + This section has no argparse flags. |
| 71 | +
|
| 72 | +More Notes: |
| 73 | + Also plain text. |
| 74 | +""" |
| 75 | + |
| 76 | + assert parse_help_sections(output) == [] |
| 77 | + |
0 commit comments