1- from typing import Any , Dict , List , Union , Optional
2- from pathlib import Path
1+ from typing import Any , Dict , List , Optional , Union
2+
33import ruamel .yaml as yaml
44from docassemble .base .util import log , DADict , DAList , DAStore , path_and_mimetype
55from packaging .version import Version
2121]
2222
2323
24+ _CAPABILITY_LOAD_DEFAULTS : Dict [str , Any ] = {
25+ "base" : "docassemble.ALWeaver" ,
26+ "minimum_version" : "1.5" ,
27+ "include_playground" : False ,
28+ }
29+
30+
31+ _capability_cache : Optional [Dict [str , Any ]] = None
32+
33+
2434def _package_name (package_name : Optional [str ] = None ):
2535 """Get package name without the name of the current module, like: docassemble.ALWeaver instead of
2636 docassemble.ALWeaver.advertise_capabilities"""
@@ -49,8 +59,10 @@ def __str__(self):
4959
5060
5161def load_capabilities (
52- base : str = "docassemble.ALWeaver" , minimum_version = "1.5" , include_playground = False
53- ):
62+ base : str = "docassemble.ALWeaver" ,
63+ minimum_version : str = "1.5" ,
64+ include_playground : bool = False ,
65+ ) -> Dict [str , Any ]:
5466 """
5567 Load and return a dictionary containing all advertised capabilities matching
5668 the specified minimum version, and optionally include capabilities that were
@@ -67,10 +79,9 @@ def load_capabilities(
6779 weaverdata .get ("published_configuration_capabilities" ) or {}
6880 )
6981 try :
82+ yaml_loader = yaml .YAML (typ = "safe" , pure = True )
7083 with open (this_yaml ) as f :
71- this_yaml_contents = f .read ()
72-
73- first_file = list (yaml .safe_load_all (this_yaml_contents ))[0 ]
84+ first_file = yaml_loader .load (f )
7485
7586 capabilities = {"Default configuration" : first_file }
7687 except :
@@ -96,41 +107,45 @@ def load_capabilities(
96107 f"{ package_name } :data/sources/{ published_configuration_capabilities [package_name ][0 ]} "
97108 )[0 ]
98109 try :
110+ yaml_loader = yaml .YAML (typ = "safe" , pure = True )
99111 with open (path ) as f :
100- yaml_contents = f .read ()
101- capabilities [package_name ] = list (yaml .safe_load_all (yaml_contents ))[0 ]
112+ capabilities [package_name ] = yaml_loader .load (f )
102113 except :
103114 log (f"Unable to load published Weaver configuration file { path } " )
104115
105116 return capabilities
106117
107118
108- _al_weaver_capabilities = load_capabilities ()
119+ def _get_capabilities (refresh : bool = False ) -> Dict [str , Any ]:
120+ """Return cached capabilities, optionally refreshing from the datastore."""
121+
122+ global _capability_cache
123+ if refresh or _capability_cache is None :
124+ _capability_cache = load_capabilities (** _CAPABILITY_LOAD_DEFAULTS )
125+ return _capability_cache
109126
110127
111128def get_possible_deps_as_choices (dep_category = None ):
112129 """Gets the possible yml files that the generated interview will depend on"""
113130
114131 dep_choices = []
115132
133+ capabilities = _get_capabilities ()
134+
116135 # TODO: do we want to prefix the choice with the package name?
117- for capability in _al_weaver_capabilities :
136+ for capability in capabilities :
118137 if dep_category == "organization" :
119138 dep_choices .extend (
120139 [
121140 {item .get ("include_name" ): item .get ("description" )}
122- for item in _al_weaver_capabilities [capability ].get (
123- "organization_choices" , []
124- )
141+ for item in capabilities [capability ].get ("organization_choices" , [])
125142 ]
126143 )
127144 elif dep_category == "jurisdiction" :
128145 dep_choices .extend (
129146 [
130147 {item .get ("include_name" ): item .get ("description" )}
131- for item in _al_weaver_capabilities [capability ].get (
132- "jurisdiction_choices" , []
133- )
148+ for item in capabilities [capability ].get ("jurisdiction_choices" , [])
134149 ]
135150 )
136151
@@ -146,14 +161,14 @@ def get_pypi_deps_from_choices(choices: Union[List[str], DADict]):
146161 else : # List
147162 choice_list = choices
148163
149- for capability in _al_weaver_capabilities :
164+ capabilities = _get_capabilities ()
165+
166+ for capability in capabilities :
150167 pypi_deps .extend (
151168 [
152169 choice .get ("dependency" )
153- for choice in _al_weaver_capabilities [capability ].get (
154- "organization_choices" , []
155- )
156- + _al_weaver_capabilities [capability ].get ("jurisdiction_choices" , [])
170+ for choice in capabilities [capability ].get ("organization_choices" , [])
171+ + capabilities [capability ].get ("jurisdiction_choices" , [])
157172 if choice .get ("dependency" )
158173 and choice .get ("include_name" ) in choice_list
159174 ]
@@ -178,16 +193,14 @@ def get_full_dep_details(dep_category: Optional[str] = None) -> List:
178193 filtered and used as needed."""
179194 dep_choices = []
180195
196+ capabilities = _get_capabilities ()
197+
181198 # TODO: do we want to prefix the choice with the package name?
182- for capability in _al_weaver_capabilities :
199+ for capability in capabilities :
183200 if dep_category == "organization" :
184- dep_choices .extend (
185- _al_weaver_capabilities [capability ].get ("organization_choices" , [])
186- )
201+ dep_choices .extend (capabilities [capability ].get ("organization_choices" , []))
187202 elif dep_category == "jurisdiction" :
188- dep_choices .extend (
189- _al_weaver_capabilities [capability ].get ("jurisdiction_choices" , [])
190- )
203+ dep_choices .extend (capabilities [capability ].get ("jurisdiction_choices" , []))
191204
192205 return list (unique_everseen (dep_choices ))
193206
@@ -200,7 +213,9 @@ def get_matching_deps(
200213 dep_choices = []
201214
202215 # TODO: do we want to prefix the choice with the package name?
203- for capability in _al_weaver_capabilities .values ():
216+ capabilities = _get_capabilities ()
217+
218+ for capability in capabilities .values ():
204219 if dep_category == "organization" :
205220 dep_choices .extend (
206221 [
@@ -234,7 +249,9 @@ def get_output_mako_choices() -> Dict[str, str]:
234249 the interview YAML file. It will be one deep.
235250 """
236251 choices = {}
237- for key , capability in _al_weaver_capabilities .items ():
252+ capabilities = _get_capabilities ()
253+
254+ for key , capability in capabilities .items ():
238255 if capability .get ("output_mako" ):
239256 if isinstance (capability ["output_mako" ], str ):
240257 choices [key ] = capability ["output_mako" ]
@@ -309,3 +326,10 @@ def advertise_capabilities(
309326 weaverdata .set (
310327 "published_configuration_capabilities" , published_configuration_capabilities
311328 )
329+ global _CAPABILITY_LOAD_DEFAULTS
330+ _CAPABILITY_LOAD_DEFAULTS = {
331+ ** _CAPABILITY_LOAD_DEFAULTS ,
332+ "base" : base ,
333+ "minimum_version" : minimum_version ,
334+ }
335+ _get_capabilities (refresh = True )
0 commit comments