2424
2525if t .TYPE_CHECKING :
2626 from sqlglot .dialects .dialect import DialectType
27+ from sqlmesh .utils import registry_decorator
2728 from sqlmesh .utils .jinja import MacroReference
2829
30+ MacroCallable = registry_decorator
31+
2932
3033def make_python_env (
31- expressions : t .Union [exp .Expression , t .List [exp .Expression ]],
34+ expressions : t .Union [
35+ exp .Expression ,
36+ t .List [t .Union [exp .Expression , t .Tuple [exp .Expression , bool ]]],
37+ ],
3238 jinja_macro_references : t .Optional [t .Set [MacroReference ]],
3339 module_path : Path ,
3440 macros : MacroRegistry ,
@@ -42,53 +48,79 @@ def make_python_env(
4248) -> t .Dict [str , Executable ]:
4349 python_env = {} if python_env is None else python_env
4450 variables = variables or {}
45- env : t .Dict [str , t .Any ] = {}
46- used_macros = {}
51+ env : t .Dict [str , t .Tuple [t .Any , t .Optional [bool ]]] = {}
52+ used_macros : t .Dict [
53+ str ,
54+ t .Tuple [t .Union [Executable | MacroCallable ], t .Optional [bool ]],
55+ ] = {}
4756 used_variables = (used_variables or set ()).copy ()
4857
4958 expressions = ensure_list (expressions )
50- for expression in expressions :
51- if not isinstance (expression , d .Jinja ):
52- for macro_func_or_var in expression .find_all (d .MacroFunc , d .MacroVar , exp .Identifier ):
53- if macro_func_or_var .__class__ is d .MacroFunc :
54- name = macro_func_or_var .this .name .lower ()
55- if name in macros :
56- used_macros [name ] = macros [name ]
57- if name == c .VAR :
58- args = macro_func_or_var .this .expressions
59- if len (args ) < 1 :
60- raise_config_error ("Macro VAR requires at least one argument" , path )
61- if not args [0 ].is_string :
62- raise_config_error (
63- f"The variable name must be a string literal, '{ args [0 ].sql ()} ' was given instead" ,
64- path ,
65- )
66- used_variables .add (args [0 ].this .lower ())
67- elif macro_func_or_var .__class__ is d .MacroVar :
68- name = macro_func_or_var .name .lower ()
69- if name in macros :
70- used_macros [name ] = macros [name ]
71- elif name in variables :
72- used_variables .add (name )
73- elif (
74- isinstance (macro_func_or_var , (exp .Identifier , d .MacroStrReplace , d .MacroSQL ))
75- ) and "@" in macro_func_or_var .name :
76- for _ , identifier , braced_identifier , _ in MacroStrTemplate .pattern .findall (
77- macro_func_or_var .name
78- ):
79- var_name = braced_identifier or identifier
80- if var_name in variables :
81- used_variables .add (var_name )
59+ for expression_metadata in expressions :
60+ if isinstance (expression_metadata , tuple ):
61+ expression , is_metadata = expression_metadata
62+ else :
63+ expression , is_metadata = expression_metadata , None
64+
65+ if isinstance (expression , d .Jinja ):
66+ continue
67+
68+ for macro_func_or_var in expression .find_all (d .MacroFunc , d .MacroVar , exp .Identifier ):
69+ if macro_func_or_var .__class__ is d .MacroFunc :
70+ name = macro_func_or_var .this .name .lower ()
71+ if name not in macros :
72+ continue
73+
74+ # If this macro has been seen before as a non-metadata macro, prioritize that
75+ used_macros [name ] = (
76+ macros [name ],
77+ used_macros .get (name , (None , is_metadata ))[1 ],
78+ )
79+ if name == c .VAR :
80+ args = macro_func_or_var .this .expressions
81+ if len (args ) < 1 :
82+ raise_config_error ("Macro VAR requires at least one argument" , path )
83+ if not args [0 ].is_string :
84+ raise_config_error (
85+ f"The variable name must be a string literal, '{ args [0 ].sql ()} ' was given instead" ,
86+ path ,
87+ )
88+ used_variables .add (args [0 ].this .lower ())
89+ elif macro_func_or_var .__class__ is d .MacroVar :
90+ name = macro_func_or_var .name .lower ()
91+ if name in macros :
92+ # If this macro has been seen before as a non-metadata macro, prioritize that
93+ used_macros [name ] = (
94+ macros [name ],
95+ used_macros .get (name , (None , is_metadata ))[1 ],
96+ )
97+ elif name in variables :
98+ used_variables .add (name )
99+ elif (
100+ isinstance (macro_func_or_var , (exp .Identifier , d .MacroStrReplace , d .MacroSQL ))
101+ ) and "@" in macro_func_or_var .name :
102+ for _ , identifier , braced_identifier , _ in MacroStrTemplate .pattern .findall (
103+ macro_func_or_var .name
104+ ):
105+ var_name = braced_identifier or identifier
106+ if var_name in variables :
107+ used_variables .add (var_name )
82108
83109 for macro_ref in jinja_macro_references or set ():
84110 if macro_ref .package is None and macro_ref .name in macros :
85- used_macros [macro_ref .name ] = macros [macro_ref .name ]
111+ used_macros [macro_ref .name ] = ( macros [macro_ref .name ], None )
86112
87- for name , used_macro in used_macros .items ():
113+ for name , ( used_macro , is_metadata ) in used_macros .items ():
88114 if isinstance (used_macro , Executable ):
89115 python_env [name ] = used_macro
90116 elif not hasattr (used_macro , c .SQLMESH_BUILTIN ) and name not in python_env :
91- build_env (used_macro .func , env = env , name = name , path = module_path )
117+ build_env (
118+ used_macro .func ,
119+ env = env ,
120+ name = name ,
121+ path = module_path ,
122+ is_metadata_obj = is_metadata ,
123+ )
92124
93125 python_env .update (serialize_env (env , path = module_path ))
94126 return _add_variables_to_python_env (
0 commit comments