Skip to content

Commit 7e979e7

Browse files
committed
Fill in example title, title_abbrev, and synopsis from Category templates.
1 parent 60b8192 commit 7e979e7

File tree

6 files changed

+130
-13
lines changed

6 files changed

+130
-13
lines changed

aws_doc_sdk_examples_tools/categories.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,10 @@
33

44
from __future__ import annotations
55

6+
import re
7+
68
from pathlib import Path
7-
from typing import Any, Dict, List, Optional
9+
from typing import Any, Callable, Dict, List, Optional
810
from dataclasses import dataclass, field
911

1012
from aws_doc_sdk_examples_tools import metadata_errors
@@ -13,6 +15,22 @@
1315
)
1416

1517

18+
def fake_gotmpl(tmpl: Optional[str], service: str, action: str):
19+
if not tmpl:
20+
return
21+
values = {
22+
".ServiceEntity.Short": service,
23+
".Action": action,
24+
}
25+
return re.sub(
26+
r"{{(?P<name>[.\w]+)}}",
27+
lambda x: values[
28+
x.groupdict()["name"]
29+
], # This will be a KeyError if the replacement isn't in the values dict
30+
tmpl,
31+
)
32+
33+
1634
@dataclass
1735
class TitleInfo:
1836
title: Optional[str] = field(default=None)
@@ -44,6 +62,9 @@ def message(self):
4462
return "Category has no display value"
4563

4664

65+
empty_title_info = TitleInfo()
66+
67+
4768
@dataclass
4869
class Category:
4970
key: str
@@ -52,6 +73,23 @@ class Category:
5273
overrides: Optional[TitleInfo] = field(default=None)
5374
description: Optional[str] = field(default=None)
5475

76+
def evaluate(
77+
self,
78+
value: Optional[str],
79+
field: Callable[[TitleInfo], Optional[str]],
80+
service: str,
81+
action: str,
82+
):
83+
overrides = field(self.overrides or empty_title_info)
84+
if overrides:
85+
return fake_gotmpl(overrides, service, action)
86+
if value:
87+
return value
88+
defaults = field(self.defaults or empty_title_info)
89+
if defaults:
90+
return fake_gotmpl(defaults, service, action)
91+
return ""
92+
5593
def validate(self, errors: MetadataErrors):
5694
if not self.display:
5795
errors.append(CategoryWithNoDisplayError(id=self.key))

aws_doc_sdk_examples_tools/doc_gen.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,9 @@ def merge(self, other: "DocGen") -> MetadataErrors:
150150
self.snippet_files.update(other.snippet_files)
151151
self.cross_blocks.update(other.cross_blocks)
152152
self.extend_examples(other.examples.values(), warnings)
153+
for name, category in other.categories.items():
154+
if name not in self.categories:
155+
self.categories[name] = category
153156

154157
return warnings
155158

@@ -318,6 +321,17 @@ def validate(self):
318321
self.root,
319322
)
320323

324+
def fill_fields(self):
325+
for example in self.examples.values():
326+
service_id = example.service_main or next(
327+
k for (k, _) in example.services.items()
328+
)
329+
action = (
330+
next((k for k in example.services[service_id]), None)
331+
or example.id.split("_", 1)[1]
332+
)
333+
example.fill_title(self.categories, self.services[service_id].short, action)
334+
321335
def stats(self):
322336
values = self.examples.values()
323337
initial = defaultdict(int)

aws_doc_sdk_examples_tools/doc_gen_cli.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ def main():
5353
unmerged_doc_gen = DocGen.from_root(Path(root))
5454
merged_doc_gen.merge(unmerged_doc_gen)
5555

56+
merged_doc_gen.validate()
57+
merged_doc_gen.fill_fields()
58+
5659
if not args.skip_entity_expansion:
5760
# Replace entities
5861
merged_doc_gen.expand_entity_fields(merged_doc_gen)

aws_doc_sdk_examples_tools/doc_gen_cli_test.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import pytest
2-
from unittest.mock import patch, mock_open
2+
from unittest.mock import patch, mock_open, MagicMock
33
from argparse import Namespace
44
from pathlib import Path
55

6+
from .categories import Category
67
from .doc_gen import DocGen, MetadataError, Example
78
from .doc_gen_cli import main
8-
from .metadata import DocFilenames, Sdk, Language, SDKPageVersion, Version
9-
from .sdks import SdkVersion
9+
from .metadata import DocFilenames, Language, SDKPageVersion, Version
10+
from .sdks import Sdk, SdkVersion
11+
from .services import Service
1012

1113

1214
@pytest.fixture
@@ -46,6 +48,15 @@ def mock_doc_gen(mock_example):
4648
MetadataError(file="a.yaml", id="Error 1"),
4749
MetadataError(file="b.yaml", id="Error 2"),
4850
]
51+
doc_gen.categories = {"Actions": Category(key="Actions", display="Action")}
52+
doc_gen.services = {
53+
"medical-imaging": Service(
54+
long="&AHIlong;",
55+
short="&AHI;",
56+
sort="HealthImaging",
57+
version="medical-imaging-2023-07-19",
58+
)
59+
}
4960
doc_gen.sdks = {
5061
"JavaScript": Sdk(
5162
name="JavaScript",
@@ -60,6 +71,7 @@ def mock_doc_gen(mock_example):
6071

6172
@pytest.fixture
6273
def patched_environment(mock_doc_gen):
74+
mock_doc_gen.validate = MagicMock()
6375
with patch("argparse.ArgumentParser.parse_args") as mock_parse_args, patch(
6476
"aws_doc_sdk_examples_tools.doc_gen.DocGen.empty", return_value=mock_doc_gen
6577
), patch("aws_doc_sdk_examples_tools.doc_gen.DocGen.from_root"), patch(

aws_doc_sdk_examples_tools/doc_gen_test.py

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,10 @@
99
from pathlib import Path
1010
import json
1111

12-
from .metadata_errors import MetadataErrors, MetadataError
12+
from .categories import Category, TitleInfo
1313
from .doc_gen import DocGen, DocGenEncoder
14+
from .metadata import Example
15+
from .metadata_errors import MetadataErrors, MetadataError
1416
from .sdks import Sdk, SdkVersion
1517
from .services import Service, ServiceExpanded
1618
from .snippets import Snippet
@@ -115,7 +117,25 @@ def sample_doc_gen() -> DocGen:
115117
)
116118
},
117119
snippet_files={"test.py"},
118-
examples={},
120+
examples={
121+
"s3_PutObject": Example(
122+
"s3_PutObject",
123+
file=Path("filea.txt"),
124+
languages={},
125+
services={"s3": set(["PutObject"])},
126+
)
127+
},
128+
categories={
129+
"Actions": Category(
130+
"Actions",
131+
"Actions",
132+
defaults=TitleInfo(
133+
title="<code>{{.Action}}</code>",
134+
synopsis="{{.ServiceEntity.Short}} {{.Action}}",
135+
),
136+
overrides=TitleInfo(title_abbrev="ExcerptPartsUsage"),
137+
)
138+
},
119139
cross_blocks={"test_block"},
120140
)
121141

@@ -195,3 +215,11 @@ def test_doc_gen_load_snippets():
195215
doc_gen.collect_snippets()
196216
assert doc_gen.snippet_files == set(["snippet_file.txt"])
197217
assert doc_gen.snippets["snippet_file.txt"].code == "Line A\nLine C\n"
218+
219+
220+
def test_fill_fields(sample_doc_gen: DocGen):
221+
sample_doc_gen.fill_fields()
222+
example = sample_doc_gen.examples["s3_PutObject"]
223+
assert example.title == "<code>PutObject</code>"
224+
assert example.title_abbrev == "ExcerptPartsUsage"
225+
assert example.synopsis == "&S3; PutObject"

aws_doc_sdk_examples_tools/metadata.py

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,19 @@
66

77
from collections import defaultdict
88
from dataclasses import dataclass, field
9-
from typing import Any, Dict, Literal, List, Optional, Set, Union, Iterable
9+
from typing import Dict, Literal, List, Optional, Set, Iterable
1010
from os.path import splitext
1111
from pathlib import Path
1212

1313
from . import metadata_errors
14+
from .categories import Category
1415
from .metadata_errors import (
1516
MetadataErrors,
1617
MetadataParseError,
1718
ExampleMergeMismatchedId,
1819
ExampleMergeMismatchedLanguage,
1920
ExampleMergeConflict,
2021
)
21-
from .project_validator import ValidationConfig
22-
from .services import Service
23-
from .sdks import Sdk
2422

2523

2624
@dataclass
@@ -132,9 +130,9 @@ class Example:
132130
id: str
133131
file: Optional[Path]
134132
languages: Dict[str, Language]
135-
# Human readable title. TODO: Defaults to slug-to-title of the ID if not provided.
133+
# Human readable title.
136134
title: Optional[str] = field(default="")
137-
# Used in the TOC. TODO: Defaults to slug-to-title of the ID if not provided.
135+
# Used in the TOC.
138136
title_abbrev: Optional[str] = field(default="")
139137
synopsis: Optional[str] = field(default="")
140138
# String label categories. Categories inferred by cross-service with multiple services, and can be whatever else it wants. Controls where in the TOC it appears.
@@ -151,6 +149,30 @@ class Example:
151149
synopsis_list: List[str] = field(default_factory=list)
152150
source_key: Optional[str] = field(default=None)
153151

152+
def fill_title(self, categories: Dict[str, Category], service, action):
153+
category = self.choose_category(categories)
154+
if category:
155+
self.title = category.evaluate(
156+
self.title, lambda x: x.title, service, action
157+
)
158+
self.title_abbrev = category.evaluate(
159+
self.title_abbrev, lambda x: x.title_abbrev, service, action
160+
)
161+
self.synopsis = category.evaluate(
162+
self.synopsis, lambda x: x.synopsis, service, action
163+
)
164+
165+
def choose_category(self, categories: Dict[str, Category]) -> Optional[Category]:
166+
"""Find a category for an example. This logic is taken from directories and zexii.
167+
168+
Original Zexii code at https://code.amazon.com/packages/GoAmzn-AWSDocsCodeExampleDocBuilder/blobs/1321fffadd8ff02e6acbae4a1f42b81006cdfa72/--/zexi/zonbook/category.go#L31-L50.
169+
"""
170+
if self.category in categories:
171+
return categories[self.category]
172+
if len(self.services) == 1:
173+
return categories["Actions"]
174+
return categories["Scenarios"]
175+
154176
def merge(self, other: Example, errors: MetadataErrors):
155177
"""Combine `other` Example into self example.
156178
@@ -184,7 +206,7 @@ def merge(self, other: Example, errors: MetadataErrors):
184206
err.id = self.id
185207
err.file = self.file
186208
if hasattr(err, "other_file"):
187-
err.other_file = other.file
209+
err.other_file = other.file # type: ignore
188210
errors.extend(merge_errs)
189211

190212
def validate(self, errors: MetadataErrors, root: Path):

0 commit comments

Comments
 (0)