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 }  
81+ 
82+     def  load (self , filename : str ) ->  Tuple [Path , Any ]:
83+         path  =  f"{ self .path } { filename }  
84+         url  =  f"https://raw.githubusercontent.com/{ 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