Skip to content

Commit 494d86c

Browse files
committed
Replace argparse with typer for WRITEME flags.
This has the immediate benefit of allowing multiple '--language' and '--service' options.
1 parent 278cfef commit 494d86c

File tree

5 files changed

+135
-78
lines changed

5 files changed

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

.tools/readmes/runner.py

Lines changed: 86 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+
"--language",
64+
help="The languages of the SDK.",
65+
),
66+
] = [
67+
Language.all # type: ignore
68+
], # type: ignore
69+
services: Annotated[
70+
list[Service], # type: ignore
71+
typer.Option(
72+
"--service",
73+
help="The targeted service.",
74+
),
75+
] = [
76+
Service.all # type: ignore
77+
], # type: ignore
78+
safe: Annotated[
79+
bool,
80+
typer.Option(
81+
help="Save a copy of the original README as the 'saved_readme' value specified in config.py ({config.saved_readme})."
82+
),
83+
] = True,
84+
verbose: Annotated[
85+
bool, typer.Option(help="When set, output verbose debugging info.")
86+
] = False,
87+
dry_run: Annotated[
88+
bool,
89+
typer.Option(
90+
help="In dry run, compare current vs generated and exit with failure if they do not match."
91+
),
92+
] = False,
93+
check: Annotated[bool, typer.Option(help="Alias for --dry-run.")] = False,
94+
diff: Annotated[
95+
bool, typer.Option(help="Show a diff of READMEs that have changed.")
96+
] = False,
97+
):
98+
if "all" in languages:
99+
languages = list(Language) # type: ignore
100+
101+
if "all" in services:
102+
services = list(Service) # 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,23 @@ 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+
for language_and_version in languages:
127+
(language, version) = language_and_version.value.split(":")
110128
id = f"{language}:{version}:{service}"
111129
try:
112-
renderer.set_example(service, language, int(version), args.safe)
130+
renderer.set_example(service.value, language, int(version), safe)
113131

114132
logging.debug("Rendering %s", id)
115133
render_status = renderer.render()
116134
logging.debug("Status %s", render_status)
117135

118136
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))
137+
if dry_run:
138+
diff_text = None
139+
if diff:
140+
diff_text = make_diff(renderer, id)
141+
failed.append((id, diff_text))
124142
else:
125143
renderer.write()
126144
written.append(id)
@@ -139,10 +157,10 @@ def main():
139157
skipped.append(id)
140158
except MissingMetadataError as mme:
141159
logging.debug(mme, exc_info=True)
142-
failed.append(id)
160+
failed.append((id, None))
143161
except Exception as e:
144162
logging.error(e, exc_info=True)
145-
failed.append(id)
163+
failed.append((id, None))
146164

147165
skip_list = "\n".join(f"Skipped {f}" for f in sorted(skipped))
148166
logging.debug(skip_list or "(None Skipped)")
@@ -155,11 +173,11 @@ def main():
155173
if no_folder:
156174
no_folder_list = "\n".join(f"No folder: {f}" for f in sorted(no_folder))
157175
print(no_folder_list)
158-
if not args.dry_run:
176+
if not dry_run:
159177
done_list = "\n".join(f"Wrote {f}" for f in sorted(written))
160178
print(done_list or "(None Written)")
161179
if failed:
162-
if args.diff:
180+
if diff:
163181
failed_list = "\n".join(
164182
f"Diff: {f[1]}" for f in sorted(failed, key=lambda f: f[0])
165183
)

.tools/readmes/writeme.py

Lines changed: 12 additions & 7 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

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

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

0 commit comments

Comments
 (0)