2323from sqlmesh .core .metric import Metric , MetricMeta , expand_metrics , load_metric_ddl
2424from sqlmesh .core .model import (
2525 Model ,
26- ExternalModel ,
2726 ModelCache ,
2827 SeedModel ,
2928 create_external_model ,
@@ -59,6 +58,14 @@ class LoadedProject:
5958 user_rules : RuleSet
6059
6160
61+ class CacheBase (abc .ABC ):
62+ @abc .abstractmethod
63+ def get_or_load_models (
64+ self , target_path : Path , loader : t .Callable [[], t .List [Model ]]
65+ ) -> t .List [Model ]:
66+ """Get or load all models from cache."""
67+
68+
6269class Loader (abc .ABC ):
6370 """Abstract base class to load macros and models for a context"""
6471
@@ -192,6 +199,7 @@ def _load_metrics(self) -> UniqueKeyDict[str, MetricMeta]:
192199 def _load_external_models (
193200 self ,
194201 audits : UniqueKeyDict [str , ModelAudit ],
202+ cache : CacheBase ,
195203 gateway : t .Optional [str ] = None ,
196204 ) -> UniqueKeyDict [str , Model ]:
197205 models : UniqueKeyDict [str , Model ] = UniqueKeyDict ("models" )
@@ -208,32 +216,39 @@ def _load_external_models(
208216 if external_models_path .exists () and external_models_path .is_dir ():
209217 paths_to_load .extend (self ._glob_paths (external_models_path , extension = ".yaml" ))
210218
219+ def _load () -> t .List [Model ]:
220+ try :
221+ with open (path , "r" , encoding = "utf-8" ) as file :
222+ return [
223+ create_external_model (
224+ defaults = self .config .model_defaults .dict (),
225+ path = path ,
226+ project = self .config .project ,
227+ audit_definitions = audits ,
228+ ** {
229+ "dialect" : self .config .model_defaults .dialect ,
230+ "default_catalog" : self .context .default_catalog ,
231+ ** row ,
232+ },
233+ )
234+ for row in YAML ().load (file .read ())
235+ ]
236+ except Exception as ex :
237+ raise ConfigError (f"Failed to load model definition at '{ path } '.\n { ex } " )
238+
211239 for path in paths_to_load :
212240 self ._track_file (path )
213241
214- with open (path , "r" , encoding = "utf-8" ) as file :
215- external_models : t .List [ExternalModel ] = []
216- for row in YAML ().load (file .read ()):
217- model = create_external_model (
218- defaults = self .config .model_defaults .dict (),
219- path = path ,
220- project = self .config .project ,
221- audit_definitions = audits ,
222- ** {
223- "dialect" : self .config .model_defaults .dialect ,
224- "default_catalog" : self .context .default_catalog ,
225- ** row ,
226- },
227- )
228- external_models .append (model )
229-
230- # external models with no explicit gateway defined form the base set
231- for model in (e for e in external_models if e .gateway is None ):
242+ external_models = cache .get_or_load_models (path , _load )
243+ # external models with no explicit gateway defined form the base set
244+ for model in external_models :
245+ if model .gateway is None :
232246 models [model .fqn ] = model
233247
234- # however, if there is a gateway defined, gateway-specific models take precedence
235- if gateway :
236- for model in (e for e in external_models if e .gateway == gateway ):
248+ # however, if there is a gateway defined, gateway-specific models take precedence
249+ if gateway :
250+ for model in external_models :
251+ if model .gateway == gateway :
237252 models .update ({model .fqn : model })
238253
239254 return models
@@ -396,8 +411,9 @@ def _load_models(
396411 Loads all of the models within the model directory with their associated
397412 audits into a Dict and creates the dag
398413 """
399- sql_models = self ._load_sql_models (macros , jinja_macros , audits , signals )
400- external_models = self ._load_external_models (audits , gateway )
414+ cache = SqlMeshLoader ._Cache (self , self .config_path )
415+ sql_models = self ._load_sql_models (macros , jinja_macros , audits , signals , cache )
416+ external_models = self ._load_external_models (audits , cache , gateway )
401417 python_models = self ._load_python_models (macros , jinja_macros , audits , signals )
402418
403419 all_model_names = list (sql_models ) + list (external_models ) + list (python_models )
@@ -413,10 +429,10 @@ def _load_sql_models(
413429 jinja_macros : JinjaMacroRegistry ,
414430 audits : UniqueKeyDict [str , ModelAudit ],
415431 signals : UniqueKeyDict [str , signal ],
432+ cache : CacheBase ,
416433 ) -> UniqueKeyDict [str , Model ]:
417434 """Loads the sql models into a Dict"""
418435 models : UniqueKeyDict [str , Model ] = UniqueKeyDict ("models" )
419- cache = SqlMeshLoader ._Cache (self , self .config_path )
420436
421437 for path in self ._glob_paths (
422438 self .config_path / c .MODELS ,
@@ -662,7 +678,7 @@ def _load_linting_rules(self) -> RuleSet:
662678
663679 return RuleSet (user_rules .values ())
664680
665- class _Cache :
681+ class _Cache ( CacheBase ) :
666682 def __init__ (self , loader : SqlMeshLoader , config_path : Path ):
667683 self ._loader = loader
668684 self .config_path = config_path
0 commit comments