6262
6363logger = logging .getLogger (__name__ )
6464
65+ RUNTIME_RENDERED_MODEL_FIELDS = {
66+ "audits" ,
67+ "signals" ,
68+ "description" ,
69+ "cron" ,
70+ "physical_properties" ,
71+ "merge_filter" ,
72+ }
73+
6574
6675class _Model (ModelMeta , frozen = True ):
6776 """Model is the core abstraction for user defined datasets.
@@ -1823,7 +1832,7 @@ def load_sql_based_model(
18231832 if kind_prop .name .lower () == "merge_filter" :
18241833 unrendered_merge_filter = kind_prop
18251834
1826- meta_renderer = _meta_renderer (
1835+ rendered_meta_exprs = render_expression (
18271836 expression = meta ,
18281837 module_path = module_path ,
18291838 macros = macros ,
@@ -1834,7 +1843,6 @@ def load_sql_based_model(
18341843 default_catalog = default_catalog ,
18351844 )
18361845
1837- rendered_meta_exprs = meta_renderer .render ()
18381846 if rendered_meta_exprs is None or len (rendered_meta_exprs ) != 1 :
18391847 raise_config_error (
18401848 f"Invalid MODEL statement:\n { meta .sql (dialect = dialect , pretty = True )} " ,
@@ -2024,21 +2032,6 @@ def create_python_model(
20242032 # Also remove self-references that are found
20252033
20262034 dialect = kwargs .get ("dialect" )
2027- renderer_kwargs = {
2028- "module_path" : module_path ,
2029- "macros" : macros ,
2030- "jinja_macros" : jinja_macros ,
2031- "variables" : variables ,
2032- "path" : path ,
2033- "dialect" : dialect ,
2034- "default_catalog" : kwargs .get ("default_catalog" ),
2035- }
2036-
2037- name_renderer = _meta_renderer (
2038- expression = d .parse_one (name , dialect = dialect ),
2039- ** renderer_kwargs , # type: ignore
2040- )
2041- name = t .cast (t .List [exp .Expression ], name_renderer .render ())[0 ].sql (dialect = dialect )
20422035
20432036 dependencies_unspecified = depends_on is None
20442037
@@ -2050,15 +2043,21 @@ def create_python_model(
20502043 if dependencies_unspecified :
20512044 depends_on = parsed_depends_on - {name }
20522045 else :
2053- depends_on_renderer = _meta_renderer (
2046+ depends_on_rendered = render_expression (
20542047 expression = exp .Array (
20552048 expressions = [d .parse_one (dep , dialect = dialect ) for dep in depends_on or []]
20562049 ),
2057- ** renderer_kwargs , # type: ignore
2050+ module_path = module_path ,
2051+ macros = macros ,
2052+ jinja_macros = jinja_macros ,
2053+ variables = variables ,
2054+ path = path ,
2055+ dialect = dialect ,
2056+ default_catalog = kwargs .get ("default_catalog" ),
20582057 )
20592058 depends_on = {
20602059 dep .sql (dialect = dialect )
2061- for dep in t .cast (t .List [exp .Expression ], depends_on_renderer . render () )[0 ].expressions
2060+ for dep in t .cast (t .List [exp .Expression ], depends_on_rendered )[0 ].expressions
20622061 }
20632062
20642063 variables = {k : v for k , v in (variables or {}).items () if k in referenced_variables }
@@ -2382,7 +2381,61 @@ def _refs_to_sql(values: t.Any) -> exp.Expression:
23822381 return exp .Tuple (expressions = values )
23832382
23842383
2385- def _meta_renderer (
2384+ def render_meta_fields (
2385+ fields : t .Dict [str , t .Any ],
2386+ module_path : Path ,
2387+ path : Path ,
2388+ jinja_macros : t .Optional [JinjaMacroRegistry ],
2389+ macros : t .Optional [MacroRegistry ],
2390+ dialect : DialectType ,
2391+ variables : t .Optional [t .Dict [str , t .Any ]],
2392+ default_catalog : t .Optional [str ],
2393+ ) -> t .Dict [str , t .Any ]:
2394+ def render_field_value (value : t .Any ) -> t .Any :
2395+ if isinstance (value , exp .Expression ) or (
2396+ isinstance (value , str ) and d .SQLMESH_MACRO_PREFIX in value
2397+ ):
2398+ expression = exp .maybe_parse (value , dialect = dialect )
2399+ rendered_expr = render_expression (
2400+ expression = expression ,
2401+ module_path = module_path ,
2402+ macros = macros ,
2403+ jinja_macros = jinja_macros ,
2404+ variables = variables ,
2405+ path = path ,
2406+ dialect = dialect ,
2407+ default_catalog = default_catalog ,
2408+ )
2409+ if rendered_expr is None :
2410+ raise SQLMeshError (
2411+ f"Failed to render model attribute `{ fields ['name' ]} ` at `{ path } `\n "
2412+ f"'{ expression .sql (dialect = dialect )} ' must return an expression"
2413+ )
2414+ if len (rendered_expr ) != 1 :
2415+ raise SQLMeshError (
2416+ f"Failed to render model attribute `{ fields ['name' ]} ` at `{ path } `.\n "
2417+ f"`{ expression .sql (dialect = dialect )} ` must return one result, but got { len (rendered_expr )} "
2418+ )
2419+ return rendered_expr [0 ]
2420+
2421+ return value
2422+
2423+ for field_name , field_info in ModelMeta .all_field_infos ().items ():
2424+ field = field_info .alias or field_name
2425+ if field not in RUNTIME_RENDERED_MODEL_FIELDS and (field_value := fields .get (field )):
2426+ if isinstance (field_value , dict ):
2427+ for key in list (field_value .keys ()):
2428+ if key not in RUNTIME_RENDERED_MODEL_FIELDS :
2429+ fields [field ][key ] = render_field_value (field_value [key ])
2430+ elif isinstance (field_value , list ):
2431+ fields [field ] = [render_field_value (value ) for value in field_value ]
2432+ else :
2433+ fields [field ] = render_field_value (field_value )
2434+
2435+ return fields
2436+
2437+
2438+ def render_expression (
23862439 expression : exp .Expression ,
23872440 module_path : Path ,
23882441 path : Path ,
@@ -2391,7 +2444,7 @@ def _meta_renderer(
23912444 dialect : DialectType = None ,
23922445 variables : t .Optional [t .Dict [str , t .Any ]] = None ,
23932446 default_catalog : t .Optional [str ] = None ,
2394- ) -> ExpressionRenderer :
2447+ ) -> t . Optional [ t . List [ exp . Expression ]] :
23952448 meta_python_env = make_python_env (
23962449 expressions = expression ,
23972450 jinja_macro_references = None ,
@@ -2410,7 +2463,7 @@ def _meta_renderer(
24102463 default_catalog = default_catalog ,
24112464 quote_identifiers = False ,
24122465 normalize_identifiers = False ,
2413- )
2466+ ). render ()
24142467
24152468
24162469META_FIELD_CONVERTER : t .Dict [str , t .Callable ] = {
0 commit comments