Skip to content

Commit 64288cb

Browse files
authored
Replace argparse with typer for WRITEME flags. (#7252)
1 parent 21efcdd commit 64288cb

File tree

5 files changed

+140
-80
lines changed

5 files changed

+140
-80
lines changed

.tools/readmes/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@ cd .tools/readmes
1616
python -m venv .venv
1717
1818
# Windows
19-
.venv\Scripts\activate
19+
.venv\Scripts\activate
2020
2121
# Linux or MacOS
22-
source .venv/bin/activate
22+
source .venv/bin/activate
2323
```
2424

2525
Depending on how you have Python installed and on your operating system,
@@ -60,7 +60,7 @@ This creates a README.md file in the `python/example_code/s3` folder.
6060
- `--dry-run`, `--no-dry-run` In dry run, compare current vs generated and exit with failure if they do not match.
6161
- `--check` Verifies whether the existing README.md matches the proposed new README.md
6262
(but does not write a new README.md). This is the same check that is run by the GitHub action.
63-
63+
6464
You can get inline usage info by using the `-h` flag:
6565

6666
```

.tools/readmes/requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
jinja2>=3.0.3
22
pyyaml>=5.3.1
3+
typer==0.15.1
34
aws-doc-sdk-examples-tools @ git+https://github.com/awsdocs/aws-doc-sdk-examples-tools
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
aws_doc_sdk_examples_tools @ git+https://github.com/awsdocs/[email protected]
2+
black==24.3.0
3+
certifi==2025.1.31
4+
charset-normalizer==3.4.1
5+
click==8.1.8
6+
flake8==6.1.0
7+
idna==3.10
8+
iniconfig==2.0.0
9+
Jinja2==3.1.4
10+
markdown-it-py==3.0.0
11+
MarkupSafe==3.0.2
12+
mccabe==0.7.0
13+
mdurl==0.1.2
14+
mypy==1.8.0
15+
mypy-extensions==1.0.0
16+
packaging==24.2
17+
pathspec==0.11.2
18+
platformdirs==4.3.6
19+
pluggy==1.5.0
20+
pycodestyle==2.11.1
21+
pyflakes==3.1.0
22+
Pygments==2.19.1
23+
pytest==8.0.0
24+
PyYAML==6.0.1
25+
requests==2.32.0
26+
rich==13.9.4
27+
shellingham==1.5.4
28+
typer==0.15.1
29+
types-PyYAML==6.0.12.12
30+
typing_extensions==4.12.2
31+
urllib3==2.3.0
32+
yamale==4.0.4

.tools/readmes/runner.py

Lines changed: 90 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,28 @@
11
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
# SPDX-License-Identifier: Apache-2.0
33

4-
import argparse
5-
import config
4+
import typer
5+
from typing_extensions import Annotated
66
import logging
77
import os
8+
89
from difflib import unified_diff
10+
from enum import Enum
911
from pathlib import Path
1012
from typing import Optional
1113

12-
from render import Renderer, MissingMetadataError, RenderStatus
14+
from render import Renderer, RenderStatus, MissingMetadataError
1315
from scanner import Scanner
1416

1517
from aws_doc_sdk_examples_tools.doc_gen import DocGen
1618

19+
20+
# Default to not using Rich
21+
if "USE_RICH" not in os.environ:
22+
import typer.core
23+
24+
typer.core.rich = None # type: ignore
25+
1726
logging.basicConfig(level=os.environ.get("LOGLEVEL", "INFO").upper(), force=True)
1827

1928

@@ -35,61 +44,70 @@ def prepare_scanner(doc_gen: DocGen) -> Optional[Scanner]:
3544
return scanner
3645

3746

38-
def main():
39-
# Load all examples immediately for cross references. Trades correctness for speed.
40-
doc_gen = DocGen.from_root(Path(__file__).parent.parent.parent, incremental=True)
41-
42-
languages = doc_gen.languages()
43-
parser = argparse.ArgumentParser()
44-
parser.add_argument(
45-
"--languages",
46-
choices=[*languages] + ["all"],
47-
nargs="+",
48-
help="The languages of the SDK. Choose from: %(choices)s.",
49-
default=["all"],
50-
)
51-
52-
parser.add_argument(
53-
"--services",
54-
choices=[*doc_gen.services.keys()] + ["all"],
55-
nargs="+",
56-
help="The targeted service. Choose from: %(choices)s.",
57-
default=["all"],
58-
)
59-
parser.add_argument(
60-
"--safe",
61-
action="store_true",
62-
help=f"Save a copy of the original README as the 'saved_readme' value specified in config.py ({config.saved_readme}).",
63-
)
64-
parser.add_argument(
65-
"--verbose",
66-
action="store_true",
67-
help="When set, output verbose debugging info.",
68-
)
69-
parser.add_argument(
70-
"--dry-run",
71-
action="store_true",
72-
dest="dry_run",
73-
help="In dry run, compare current vs generated and exit with failure if they do not match.",
74-
default=False, # Change this to default false when we're ready to use this generally.
75-
)
76-
parser.add_argument("--no-dry-run", dest="dry_run", action="store_false")
77-
parser.add_argument("--check", dest="dry_run", action="store_true")
78-
parser.add_argument("--diff", action="store_true", default=False)
79-
args = parser.parse_args()
80-
81-
if "all" in args.languages:
82-
args.languages = [*languages]
83-
84-
if "all" in args.services:
85-
args.services = [*doc_gen.services.keys()]
86-
87-
if args.verbose:
47+
# Load all examples immediately for cross references. Trades correctness for speed.
48+
doc_gen = DocGen.from_root(Path(__file__).parent.parent.parent, incremental=True)
49+
50+
51+
Language = Enum(
52+
"Language", {lang: lang for lang in ([*doc_gen.languages()] + ["all"])}
53+
) # type: ignore
54+
Service = Enum(
55+
"Service", {serv: serv for serv in ([*doc_gen.services.keys()] + ["all"])}
56+
) # type: ignore
57+
58+
59+
def writeme(
60+
languages: Annotated[
61+
list[Language], # type: ignore
62+
typer.Option(
63+
help="The languages of the SDK.",
64+
),
65+
] = [
66+
Language.all.value # type: ignore
67+
], # type: ignore
68+
services: Annotated[
69+
list[Service], # type: ignore
70+
typer.Option(
71+
help="The targeted service.",
72+
),
73+
] = [
74+
Service.all.value # type: ignore
75+
], # type: ignore
76+
safe: Annotated[
77+
bool,
78+
typer.Option(
79+
help="Save a copy of the original README as the 'saved_readme' value specified in config.py ({config.saved_readme})."
80+
),
81+
] = True,
82+
verbose: Annotated[
83+
bool, typer.Option(help="When set, output verbose debugging info.")
84+
] = False,
85+
dry_run: Annotated[
86+
bool,
87+
typer.Option(
88+
help="In dry run, compare current vs generated and exit with failure if they do not match."
89+
),
90+
] = False,
91+
check: Annotated[bool, typer.Option(help="Alias for --dry-run.")] = False,
92+
diff: Annotated[
93+
bool, typer.Option(help="Show a diff of READMEs that have changed.")
94+
] = False,
95+
):
96+
if Language.all in languages: # type: ignore
97+
languages = list(Language) # type: ignore
98+
languages.remove(Language.all) # type: ignore
99+
100+
if Service.all in services: # type: ignore
101+
services = list(Service) # type: ignore
102+
services.remove(Service.all) # type: ignore
103+
104+
if verbose:
88105
logging.basicConfig(level=logging.DEBUG)
89106

90-
logging.debug(f"Args configuration: {args}")
107+
if check:
108+
dry_run = check
91109

92-
if args.dry_run:
110+
if dry_run:
93111
print("Dry run, no changes will be made.")
94112

95113
skipped = []
@@ -104,23 +122,27 @@ def main():
104122
return -1
105123

106124
renderer = Renderer(scanner)
107-
for service in args.services:
108-
for language_and_version in args.languages:
109-
(language, version) = language_and_version.split(":")
125+
for service in services:
126+
if service == Service.all: # type: ignore
127+
continue
128+
for language_and_version in languages:
129+
if language_and_version == Language.all: # type: ignore
130+
continue
131+
(language, version) = language_and_version.value.split(":")
110132
id = f"{language}:{version}:{service}"
111133
try:
112-
renderer.set_example(service, language, int(version), args.safe)
134+
renderer.set_example(service.value, language, int(version), safe)
113135

114136
logging.debug("Rendering %s", id)
115137
render_status = renderer.render()
116138
logging.debug("Status %s", render_status)
117139

118140
if render_status == RenderStatus.UPDATED:
119-
if args.dry_run:
120-
diff = None
121-
if args.diff:
122-
diff = make_diff(renderer, id)
123-
failed.append((id, diff))
141+
if dry_run:
142+
diff_text = None
143+
if diff:
144+
diff_text = make_diff(renderer, id)
145+
failed.append((id, diff_text))
124146
else:
125147
renderer.write()
126148
written.append(id)
@@ -139,10 +161,10 @@ def main():
139161
skipped.append(id)
140162
except MissingMetadataError as mme:
141163
logging.debug(mme, exc_info=True)
142-
failed.append(id)
164+
failed.append((id, None))
143165
except Exception as e:
144166
logging.error(e, exc_info=True)
145-
failed.append(id)
167+
failed.append((id, None))
146168

147169
skip_list = "\n".join(f"Skipped {f}" for f in sorted(skipped))
148170
logging.debug(skip_list or "(None Skipped)")
@@ -155,11 +177,11 @@ def main():
155177
if no_folder:
156178
no_folder_list = "\n".join(f"No folder: {f}" for f in sorted(no_folder))
157179
print(no_folder_list)
158-
if not args.dry_run:
180+
if not dry_run:
159181
done_list = "\n".join(f"Wrote {f}" for f in sorted(written))
160182
print(done_list or "(None Written)")
161183
if failed:
162-
if args.diff:
184+
if diff:
163185
failed_list = "\n".join(
164186
f"Diff: {f[1]}" for f in sorted(failed, key=lambda f: f[0])
165187
)

.tools/readmes/writeme.py

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,30 @@
22
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
33
# SPDX-License-Identifier: Apache-2.0
44

5-
import sys
6-
7-
from update import update
8-
95
# For debugging, engineers can skip update with the --no-update flag. Yes, it's
106
# a double negative, but it's quick and early in the startup because of the
117
# reliance on the side-effect imports from `update` and needing them to happen
128
# before importing runner, which means before importing the runner argparser.
139
NO_UPDATE_FLAG = "--no-update"
1410

15-
1611
if __name__ == "__main__":
12+
import sys
13+
1714
if NO_UPDATE_FLAG not in sys.argv:
15+
from update import update
16+
1817
update()
1918
else:
2019
sys.argv.remove(NO_UPDATE_FLAG)
2120

22-
# This import must remain in the main, after the update, as it depends on
23-
# importing the things that got changed during update.
24-
from runner import main
21+
# This import from runner must remain in __main__, after calling update(),
22+
# as it depends on things that got changed during update().
23+
from runner import writeme
24+
25+
from typer import run
26+
27+
run(writeme)
28+
else:
29+
from .runner import writeme
2530

26-
sys.exit(main())
31+
main = writeme

0 commit comments

Comments
 (0)