Skip to content

Commit 4faa60f

Browse files
committed
Refactor DocGen to use filesystem abstraction
1 parent 8aaa767 commit 4faa60f

File tree

2 files changed

+67
-53
lines changed

2 files changed

+67
-53
lines changed

aws_doc_sdk_examples_tools/doc_gen.py

Lines changed: 62 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
# from os import glob
1717

1818
from .categories import Category, parse as parse_categories
19+
from .fs import Fs, PathFs
1920
from .metadata import (
2021
Example,
2122
DocFilenames,
@@ -55,6 +56,7 @@ class DocGenMergeWarning(MetadataError):
5556
class DocGen:
5657
root: Path
5758
errors: MetadataErrors
59+
fs: Fs = field(default_factory=PathFs)
5860
entities: Dict[str, str] = field(default_factory=dict)
5961
prefix: Optional[str] = None
6062
validation: ValidationConfig = field(default_factory=ValidationConfig)
@@ -171,8 +173,8 @@ def extend_examples(self, examples: Iterable[Example], errors: MetadataErrors):
171173
self.examples[id] = example
172174

173175
@classmethod
174-
def empty(cls, validation: ValidationConfig = ValidationConfig()) -> "DocGen":
175-
return DocGen(root=Path("/"), errors=MetadataErrors(), validation=validation)
176+
def empty(cls, validation: ValidationConfig = ValidationConfig(), fs: Fs = PathFs()) -> "DocGen":
177+
return DocGen(root=Path("/"), errors=MetadataErrors(), validation=validation, fs=fs)
176178

177179
@classmethod
178180
def default(cls) -> "DocGen":
@@ -190,6 +192,7 @@ def clone(self) -> "DocGen":
190192
snippet_files=set(),
191193
cross_blocks=set(),
192194
examples={},
195+
fs=self.fs,
193196
)
194197

195198
def for_root(
@@ -199,7 +202,7 @@ def for_root(
199202

200203
config = config or Path(__file__).parent / "config"
201204

202-
doc_gen = DocGen.empty()
205+
doc_gen = DocGen.empty(fs=self.fs)
203206
parse_config(doc_gen, root, config, self.validation.strict_titles)
204207
self.merge(doc_gen)
205208

@@ -209,31 +212,31 @@ def for_root(
209212
return self
210213

211214
def find_and_process_metadata(self, metadata_path: Path):
212-
for path in metadata_path.glob("*_metadata.yaml"):
215+
for path in self.fs.glob(metadata_path, "*_metadata.yaml"):
213216
self.process_metadata(path)
214217

215218
def process_metadata(self, path: Path) -> "DocGen":
216219
if path in self._loaded:
217220
return self
218221
try:
219-
with open(path) as file:
220-
examples, errs = parse_examples(
221-
path,
222-
yaml.safe_load(file),
223-
self.sdks,
224-
self.services,
225-
self.standard_categories,
226-
self.cross_blocks,
227-
self.validation,
228-
)
229-
self.extend_examples(examples, self.errors)
230-
self.errors.extend(errs)
231-
for example in examples:
232-
for lang in example.languages:
233-
language = example.languages[lang]
234-
for version in language.versions:
235-
for excerpt in version.excerpts:
236-
self.snippet_files.update(excerpt.snippet_files)
222+
content = self.fs.read(path)
223+
examples, errs = parse_examples(
224+
path,
225+
yaml.safe_load(content),
226+
self.sdks,
227+
self.services,
228+
self.standard_categories,
229+
self.cross_blocks,
230+
self.validation,
231+
)
232+
self.extend_examples(examples, self.errors)
233+
self.errors.extend(errs)
234+
for example in examples:
235+
for lang in example.languages:
236+
language = example.languages[lang]
237+
for version in language.versions:
238+
for excerpt in version.excerpts:
239+
self.snippet_files.update(excerpt.snippet_files)
237240
self._loaded.add(path)
238241
except ParserError as e:
239242
self.errors.append(YamlParseError(file=path, parser_error=str(e)))
@@ -246,8 +249,9 @@ def from_root(
246249
config: Optional[Path] = None,
247250
validation: ValidationConfig = ValidationConfig(),
248251
incremental: bool = False,
252+
fs: Fs = PathFs(),
249253
) -> "DocGen":
250-
return DocGen.empty(validation=validation).for_root(
254+
return DocGen.empty(validation=validation, fs=fs).for_root(
251255
root, config, incremental=incremental
252256
)
253257

@@ -348,6 +352,10 @@ def default(self, obj):
348352
"__entity_errors__": [{error.entity: error.message()} for error in obj]
349353
}
350354

355+
if isinstance(obj, Fs):
356+
# Don't serialize filesystem objects for security
357+
return {"__fs__": obj.__class__.__name__}
358+
351359
if isinstance(obj, set):
352360
return {"__set__": list(obj)}
353361

@@ -356,64 +364,65 @@ def default(self, obj):
356364

357365
def parse_config(doc_gen: DocGen, root: Path, config: Path, strict: bool):
358366
try:
359-
with open(root / ".doc_gen" / "validation.yaml", encoding="utf-8") as file:
360-
validation = yaml.safe_load(file)
361-
validation = validation or {}
362-
doc_gen.validation.allow_list.update(validation.get("allow_list", []))
363-
doc_gen.validation.sample_files.update(validation.get("sample_files", []))
367+
content = doc_gen.fs.read(root / ".doc_gen" / "validation.yaml")
368+
validation = yaml.safe_load(content)
369+
validation = validation or {}
370+
doc_gen.validation.allow_list.update(validation.get("allow_list", []))
371+
doc_gen.validation.sample_files.update(validation.get("sample_files", []))
364372
except Exception:
365373
pass
366374

367375
try:
368376
sdk_path = config / "sdks.yaml"
369-
with sdk_path.open(encoding="utf-8") as file:
370-
meta = yaml.safe_load(file)
371-
sdks, errs = parse_sdks(sdk_path, meta, strict)
372-
doc_gen.sdks = sdks
373-
doc_gen.errors.extend(errs)
377+
content = doc_gen.fs.read(sdk_path)
378+
meta = yaml.safe_load(content)
379+
sdks, errs = parse_sdks(sdk_path, meta, strict)
380+
doc_gen.sdks = sdks
381+
doc_gen.errors.extend(errs)
374382
except Exception:
375383
pass
376384

377385
try:
378386
services_path = config / "services.yaml"
379-
with services_path.open(encoding="utf-8") as file:
380-
meta = yaml.safe_load(file)
381-
services, service_errors = parse_services(services_path, meta)
382-
doc_gen.services = services
383-
for service in doc_gen.services.values():
384-
if service.expanded:
385-
doc_gen.entities[service.long] = service.expanded.long
386-
doc_gen.entities[service.short] = service.expanded.short
387-
doc_gen.errors.extend(service_errors)
387+
content = doc_gen.fs.read(services_path)
388+
meta = yaml.safe_load(content)
389+
services, service_errors = parse_services(services_path, meta)
390+
doc_gen.services = services
391+
for service in doc_gen.services.values():
392+
if service.expanded:
393+
doc_gen.entities[service.long] = service.expanded.long
394+
doc_gen.entities[service.short] = service.expanded.short
395+
doc_gen.errors.extend(service_errors)
388396
except Exception:
389397
pass
390398

391399
try:
392400
categories_path = config / "categories.yaml"
393-
with categories_path.open(encoding="utf-8") as file:
394-
meta = yaml.safe_load(file)
395-
standard_categories, categories, errs = parse_categories(
396-
categories_path, meta
397-
)
398-
doc_gen.standard_categories = standard_categories
399-
doc_gen.categories = categories
400-
doc_gen.errors.extend(errs)
401+
content = doc_gen.fs.read(categories_path)
402+
meta = yaml.safe_load(content)
403+
standard_categories, categories, errs = parse_categories(
404+
categories_path, meta
405+
)
406+
doc_gen.standard_categories = standard_categories
407+
doc_gen.categories = categories
408+
doc_gen.errors.extend(errs)
401409
except Exception:
402410
pass
403411

404412
try:
405413
entities_config_path = config / "entities.yaml"
406-
with entities_config_path.open(encoding="utf-8") as file:
407-
entities_config = yaml.safe_load(file)
414+
content = doc_gen.fs.read(entities_config_path)
415+
entities_config = yaml.safe_load(content)
408416
for entity, expanded in entities_config["expanded_override"].items():
409417
doc_gen.entities[entity] = expanded
410418
except Exception:
411419
pass
412420

413421
metadata = root / ".doc_gen/metadata"
414422
try:
423+
cross_content_path = metadata.parent / "cross-content"
415424
doc_gen.cross_blocks = set(
416-
[path.name for path in (metadata.parent / "cross-content").glob("*.xml")]
425+
[path.name for path in doc_gen.fs.glob(cross_content_path, "*.xml")]
417426
)
418427
except Exception:
419428
pass

aws_doc_sdk_examples_tools/doc_gen_test.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,17 @@
1616
from .sdks import Sdk, SdkVersion
1717
from .services import Service, ServiceExpanded
1818
from .snippets import Snippet
19+
from .fs import PathFs
1920

21+
SHARED_FS = PathFs()
2022

2123
@pytest.mark.parametrize(
2224
["a", "b", "d"],
2325
[
2426
(
2527
DocGen(
2628
root=Path("/a"),
29+
fs = SHARED_FS,
2730
errors=MetadataErrors(),
2831
sdks={
2932
"a": Sdk(
@@ -43,6 +46,7 @@
4346
),
4447
DocGen(
4548
root=Path("/b"),
49+
fs = SHARED_FS,
4650
errors=MetadataErrors(),
4751
sdks={
4852
"b": Sdk(
@@ -62,6 +66,7 @@
6266
),
6367
DocGen(
6468
root=Path("/a"),
69+
fs = SHARED_FS,
6570
errors=MetadataErrors(),
6671
sdks={
6772
"a": Sdk(

0 commit comments

Comments
 (0)