@@ -145,6 +145,8 @@ def _add_variables_to_python_env(
145145 python_env ,
146146 None ,
147147 strict_resolution = strict_resolution ,
148+ variables = variables ,
149+ blueprint_variables = blueprint_variables ,
148150 )
149151 used_variables = (used_variables or set ()) | python_used_variables
150152
@@ -163,7 +165,11 @@ def _add_variables_to_python_env(
163165
164166
165167def parse_dependencies (
166- python_env : t .Dict [str , Executable ], entrypoint : t .Optional [str ], strict_resolution : bool = True
168+ python_env : t .Dict [str , Executable ],
169+ entrypoint : t .Optional [str ],
170+ strict_resolution : bool = True ,
171+ variables : t .Optional [t .Dict [str , t .Any ]] = None ,
172+ blueprint_variables : t .Optional [t .Dict [str , t .Any ]] = None ,
167173) -> t .Tuple [t .Set [str ], t .Set [str ]]:
168174 """
169175 Parses the source of a model function and finds upstream table dependencies
@@ -174,13 +180,29 @@ def parse_dependencies(
174180 entrypoint: The name of the function.
175181 strict_resolution: If true, the arguments of `table` and `resolve_table` calls must
176182 be resolvable at parse time, otherwise an exception will be raised.
183+ variables: The variables available to the python environment.
184+ blueprint_variables: The blueprint variables available to the python environment.
177185
178186 Returns:
179187 A tuple containing the set of upstream table dependencies and the set of referenced variables.
180188 """
189+
190+ class VariableResolutionContext :
191+ """This enables calls like `resolve_table` to reference `var()` and `blueprint_var()`."""
192+
193+ @staticmethod
194+ def var (var_name : str , default : t .Optional [t .Any ] = None ) -> t .Optional [t .Any ]:
195+ return (variables or {}).get (var_name .lower (), default )
196+
197+ @staticmethod
198+ def blueprint_var (var_name : str , default : t .Optional [t .Any ] = None ) -> t .Optional [t .Any ]:
199+ return (blueprint_variables or {}).get (var_name .lower (), default )
200+
181201 env = prepare_env (python_env )
202+ local_env = dict .fromkeys (("context" , "evaluator" ), VariableResolutionContext )
203+
182204 depends_on = set ()
183- variables = set ()
205+ used_variables = set ()
184206
185207 for executable in python_env .values ():
186208 if not executable .is_definition :
@@ -206,7 +228,7 @@ def get_first_arg(keyword_arg_name: str) -> t.Any:
206228
207229 try :
208230 expression = to_source (first_arg )
209- return eval (expression , env )
231+ return eval (expression , env , local_env )
210232 except Exception :
211233 if strict_resolution :
212234 raise ConfigError (
@@ -217,25 +239,25 @@ def get_first_arg(keyword_arg_name: str) -> t.Any:
217239 if func .value .id == "context" and func .attr in ("table" , "resolve_table" ):
218240 depends_on .add (get_first_arg ("model_name" ))
219241 elif func .value .id in ("context" , "evaluator" ) and func .attr == c .VAR :
220- variables .add (get_first_arg ("var_name" ).lower ())
242+ used_variables .add (get_first_arg ("var_name" ).lower ())
221243 elif (
222244 isinstance (node , ast .Attribute )
223245 and isinstance (node .value , ast .Name )
224246 and node .value .id in ("context" , "evaluator" )
225247 and node .attr == c .GATEWAY
226248 ):
227249 # Check whether the gateway attribute is referenced.
228- variables .add (c .GATEWAY )
250+ used_variables .add (c .GATEWAY )
229251 elif isinstance (node , ast .FunctionDef ) and node .name == entrypoint :
230- variables .update (
252+ used_variables .update (
231253 [
232254 arg .arg
233255 for arg in [* node .args .args , * node .args .kwonlyargs ]
234256 if arg .arg != "context"
235257 ]
236258 )
237259
238- return depends_on , variables
260+ return depends_on , used_variables
239261
240262
241263def single_value_or_tuple (values : t .Sequence ) -> exp .Identifier | exp .Tuple :
0 commit comments