sqlmesh.dbt.package
1from __future__ import annotations 2 3import logging 4import typing as t 5from pathlib import Path 6 7from sqlmesh.dbt.common import PROJECT_FILENAME, Dependencies, load_yaml 8from sqlmesh.dbt.model import ModelConfig 9from sqlmesh.dbt.seed import SeedConfig 10from sqlmesh.dbt.source import SourceConfig 11from sqlmesh.dbt.test import TestConfig 12from sqlmesh.utils.errors import ConfigError 13from sqlmesh.utils.jinja import MacroInfo 14from sqlmesh.utils.pydantic import PydanticModel 15 16if t.TYPE_CHECKING: 17 from sqlmesh.dbt.context import DbtContext 18 19 20logger = logging.getLogger(__name__) 21 22 23class MacroConfig(PydanticModel): 24 """Class to contain macro configuration""" 25 26 info: MacroInfo 27 dependencies: Dependencies 28 path: Path 29 30 31class HookConfig(PydanticModel): 32 """Class to contain on run start / on run end hooks.""" 33 34 sql: str 35 index: int 36 path: Path 37 dependencies: Dependencies 38 39 40class MaterializationConfig(PydanticModel): 41 """Class to contain custom materialization configuration.""" 42 43 name: str 44 adapter: str 45 definition: str 46 dependencies: Dependencies 47 path: Path 48 49 50class Package(PydanticModel): 51 """Class to contain package configuration""" 52 53 name: str 54 tests: t.Dict[str, TestConfig] 55 sources: t.Dict[str, SourceConfig] 56 seeds: t.Dict[str, SeedConfig] 57 models: t.Dict[str, ModelConfig] 58 variables: t.Dict[str, t.Any] 59 macros: t.Dict[str, MacroConfig] 60 materializations: t.Dict[str, MaterializationConfig] 61 on_run_start: t.Dict[str, HookConfig] 62 on_run_end: t.Dict[str, HookConfig] 63 files: t.Set[Path] 64 65 @property 66 def macro_infos(self) -> t.Dict[str, MacroInfo]: 67 return {name: macro.info for name, macro in self.macros.items()} 68 69 70class PackageLoader: 71 """Loader for DBT packages""" 72 73 def __init__(self, context: DbtContext): 74 self._context = context 75 76 def load(self, package_root: Path) -> Package: 77 """ 78 Loads the specified package. 79 80 Returns: 81 Package containing the configuration found within this package 82 """ 83 logger.debug("Loading package at '%s'.", package_root) 84 project_file_path = package_root / PROJECT_FILENAME 85 logger.debug("Processing project file '%s'.", project_file_path) 86 if not project_file_path.exists(): 87 raise ConfigError(f"Could not find {PROJECT_FILENAME} in '{package_root}'.") 88 89 project_yaml = load_yaml(project_file_path) 90 package_name = self._context.render(project_yaml.get("name", "")) 91 if not package_name: 92 raise ConfigError(f"Package '{package_root}' must include package name.") 93 94 # Only include globally-scoped variables (i.e. filter out the package-scoped ones) 95 logger.debug("Processing project variables.") 96 97 all_variables = project_yaml.get("vars") or {} 98 all_variables.update(all_variables.pop(package_name, None) or {}) 99 100 package_variables = { 101 var: value for var, value in all_variables.items() if not isinstance(value, dict) 102 } 103 104 tests = _fix_paths(self._context.manifest.tests(package_name), package_root) 105 models = _fix_paths(self._context.manifest.models(package_name), package_root) 106 seeds = _fix_paths(self._context.manifest.seeds(package_name), package_root) 107 macros = _fix_paths(self._context.manifest.macros(package_name), package_root) 108 materializations = _fix_paths(self._context.manifest.materializations(), package_root) 109 on_run_start = _fix_paths(self._context.manifest.on_run_start(package_name), package_root) 110 on_run_end = _fix_paths(self._context.manifest.on_run_end(package_name), package_root) 111 sources = self._context.manifest.sources(package_name) 112 113 config_paths = { 114 config.path.absolute() # type: ignore 115 for configs in [models.values(), seeds.values(), macros.values()] 116 for config in configs 117 } 118 for path in package_root.glob("**/*.y*ml"): 119 config_paths.add(path.absolute()) 120 121 return Package( 122 name=package_name, 123 tests=tests, 124 models=models, 125 sources=sources, 126 seeds=seeds, 127 variables=package_variables, 128 macros=macros, 129 materializations=materializations, 130 files=config_paths, 131 on_run_start=on_run_start, 132 on_run_end=on_run_end, 133 ) 134 135 136T = t.TypeVar( 137 "T", TestConfig, ModelConfig, MacroConfig, MaterializationConfig, SeedConfig, HookConfig 138) 139 140 141def _fix_paths(configs: t.Dict[str, T], package_root: Path) -> t.Dict[str, T]: 142 return { 143 name: config.copy(update={"path": package_root / config.path}) 144 for name, config in configs.items() 145 }
logger =
<Logger sqlmesh.dbt.package (WARNING)>
24class MacroConfig(PydanticModel): 25 """Class to contain macro configuration""" 26 27 info: MacroInfo 28 dependencies: Dependencies 29 path: Path
Class to contain macro configuration
dependencies: sqlmesh.dbt.common.Dependencies
model_config =
{'json_encoders': {<class 'sqlglot.expressions.core.Expr'>: <function _expression_encoder>, <class 'sqlglot.expressions.datatypes.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.query.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.query.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.query.Query, sqlmesh.core.dialect.JinjaQuery, sqlmesh.core.dialect.MacroFunc]: <function _expression_encoder>, <class 'datetime.tzinfo'>: <function PydanticModel.<lambda>>}, 'arbitrary_types_allowed': True, 'extra': 'forbid', 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_fields
- model_computed_fields
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- parse_file
- from_orm
- construct
- schema
- schema_json
- validate
- update_forward_refs
32class HookConfig(PydanticModel): 33 """Class to contain on run start / on run end hooks.""" 34 35 sql: str 36 index: int 37 path: Path 38 dependencies: Dependencies
Class to contain on run start / on run end hooks.
dependencies: sqlmesh.dbt.common.Dependencies
model_config =
{'json_encoders': {<class 'sqlglot.expressions.core.Expr'>: <function _expression_encoder>, <class 'sqlglot.expressions.datatypes.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.query.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.query.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.query.Query, sqlmesh.core.dialect.JinjaQuery, sqlmesh.core.dialect.MacroFunc]: <function _expression_encoder>, <class 'datetime.tzinfo'>: <function PydanticModel.<lambda>>}, 'arbitrary_types_allowed': True, 'extra': 'forbid', 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_fields
- model_computed_fields
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- parse_file
- from_orm
- construct
- schema
- schema_json
- validate
- update_forward_refs
41class MaterializationConfig(PydanticModel): 42 """Class to contain custom materialization configuration.""" 43 44 name: str 45 adapter: str 46 definition: str 47 dependencies: Dependencies 48 path: Path
Class to contain custom materialization configuration.
dependencies: sqlmesh.dbt.common.Dependencies
model_config =
{'json_encoders': {<class 'sqlglot.expressions.core.Expr'>: <function _expression_encoder>, <class 'sqlglot.expressions.datatypes.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.query.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.query.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.query.Query, sqlmesh.core.dialect.JinjaQuery, sqlmesh.core.dialect.MacroFunc]: <function _expression_encoder>, <class 'datetime.tzinfo'>: <function PydanticModel.<lambda>>}, 'arbitrary_types_allowed': True, 'extra': 'forbid', 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_fields
- model_computed_fields
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- parse_file
- from_orm
- construct
- schema
- schema_json
- validate
- update_forward_refs
51class Package(PydanticModel): 52 """Class to contain package configuration""" 53 54 name: str 55 tests: t.Dict[str, TestConfig] 56 sources: t.Dict[str, SourceConfig] 57 seeds: t.Dict[str, SeedConfig] 58 models: t.Dict[str, ModelConfig] 59 variables: t.Dict[str, t.Any] 60 macros: t.Dict[str, MacroConfig] 61 materializations: t.Dict[str, MaterializationConfig] 62 on_run_start: t.Dict[str, HookConfig] 63 on_run_end: t.Dict[str, HookConfig] 64 files: t.Set[Path] 65 66 @property 67 def macro_infos(self) -> t.Dict[str, MacroInfo]: 68 return {name: macro.info for name, macro in self.macros.items()}
Class to contain package configuration
tests: Dict[str, sqlmesh.dbt.test.TestConfig]
sources: Dict[str, sqlmesh.dbt.source.SourceConfig]
seeds: Dict[str, sqlmesh.dbt.seed.SeedConfig]
models: Dict[str, sqlmesh.dbt.model.ModelConfig]
macros: Dict[str, MacroConfig]
materializations: Dict[str, MaterializationConfig]
on_run_start: Dict[str, HookConfig]
on_run_end: Dict[str, HookConfig]
macro_infos: Dict[str, sqlmesh.utils.jinja.MacroInfo]
model_config =
{'json_encoders': {<class 'sqlglot.expressions.core.Expr'>: <function _expression_encoder>, <class 'sqlglot.expressions.datatypes.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.query.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.query.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.query.Query, sqlmesh.core.dialect.JinjaQuery, sqlmesh.core.dialect.MacroFunc]: <function _expression_encoder>, <class 'datetime.tzinfo'>: <function PydanticModel.<lambda>>}, 'arbitrary_types_allowed': True, 'extra': 'forbid', 'protected_namespaces': ()}
Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].
Inherited Members
- pydantic.main.BaseModel
- BaseModel
- model_fields
- model_computed_fields
- model_extra
- model_fields_set
- model_construct
- model_copy
- model_dump
- model_dump_json
- model_json_schema
- model_parametrized_name
- model_post_init
- model_rebuild
- model_validate
- model_validate_json
- model_validate_strings
- parse_file
- from_orm
- construct
- schema
- schema_json
- validate
- update_forward_refs
class
PackageLoader:
71class PackageLoader: 72 """Loader for DBT packages""" 73 74 def __init__(self, context: DbtContext): 75 self._context = context 76 77 def load(self, package_root: Path) -> Package: 78 """ 79 Loads the specified package. 80 81 Returns: 82 Package containing the configuration found within this package 83 """ 84 logger.debug("Loading package at '%s'.", package_root) 85 project_file_path = package_root / PROJECT_FILENAME 86 logger.debug("Processing project file '%s'.", project_file_path) 87 if not project_file_path.exists(): 88 raise ConfigError(f"Could not find {PROJECT_FILENAME} in '{package_root}'.") 89 90 project_yaml = load_yaml(project_file_path) 91 package_name = self._context.render(project_yaml.get("name", "")) 92 if not package_name: 93 raise ConfigError(f"Package '{package_root}' must include package name.") 94 95 # Only include globally-scoped variables (i.e. filter out the package-scoped ones) 96 logger.debug("Processing project variables.") 97 98 all_variables = project_yaml.get("vars") or {} 99 all_variables.update(all_variables.pop(package_name, None) or {}) 100 101 package_variables = { 102 var: value for var, value in all_variables.items() if not isinstance(value, dict) 103 } 104 105 tests = _fix_paths(self._context.manifest.tests(package_name), package_root) 106 models = _fix_paths(self._context.manifest.models(package_name), package_root) 107 seeds = _fix_paths(self._context.manifest.seeds(package_name), package_root) 108 macros = _fix_paths(self._context.manifest.macros(package_name), package_root) 109 materializations = _fix_paths(self._context.manifest.materializations(), package_root) 110 on_run_start = _fix_paths(self._context.manifest.on_run_start(package_name), package_root) 111 on_run_end = _fix_paths(self._context.manifest.on_run_end(package_name), package_root) 112 sources = self._context.manifest.sources(package_name) 113 114 config_paths = { 115 config.path.absolute() # type: ignore 116 for configs in [models.values(), seeds.values(), macros.values()] 117 for config in configs 118 } 119 for path in package_root.glob("**/*.y*ml"): 120 config_paths.add(path.absolute()) 121 122 return Package( 123 name=package_name, 124 tests=tests, 125 models=models, 126 sources=sources, 127 seeds=seeds, 128 variables=package_variables, 129 macros=macros, 130 materializations=materializations, 131 files=config_paths, 132 on_run_start=on_run_start, 133 on_run_end=on_run_end, 134 )
Loader for DBT packages
PackageLoader(context: sqlmesh.dbt.context.DbtContext)
77 def load(self, package_root: Path) -> Package: 78 """ 79 Loads the specified package. 80 81 Returns: 82 Package containing the configuration found within this package 83 """ 84 logger.debug("Loading package at '%s'.", package_root) 85 project_file_path = package_root / PROJECT_FILENAME 86 logger.debug("Processing project file '%s'.", project_file_path) 87 if not project_file_path.exists(): 88 raise ConfigError(f"Could not find {PROJECT_FILENAME} in '{package_root}'.") 89 90 project_yaml = load_yaml(project_file_path) 91 package_name = self._context.render(project_yaml.get("name", "")) 92 if not package_name: 93 raise ConfigError(f"Package '{package_root}' must include package name.") 94 95 # Only include globally-scoped variables (i.e. filter out the package-scoped ones) 96 logger.debug("Processing project variables.") 97 98 all_variables = project_yaml.get("vars") or {} 99 all_variables.update(all_variables.pop(package_name, None) or {}) 100 101 package_variables = { 102 var: value for var, value in all_variables.items() if not isinstance(value, dict) 103 } 104 105 tests = _fix_paths(self._context.manifest.tests(package_name), package_root) 106 models = _fix_paths(self._context.manifest.models(package_name), package_root) 107 seeds = _fix_paths(self._context.manifest.seeds(package_name), package_root) 108 macros = _fix_paths(self._context.manifest.macros(package_name), package_root) 109 materializations = _fix_paths(self._context.manifest.materializations(), package_root) 110 on_run_start = _fix_paths(self._context.manifest.on_run_start(package_name), package_root) 111 on_run_end = _fix_paths(self._context.manifest.on_run_end(package_name), package_root) 112 sources = self._context.manifest.sources(package_name) 113 114 config_paths = { 115 config.path.absolute() # type: ignore 116 for configs in [models.values(), seeds.values(), macros.values()] 117 for config in configs 118 } 119 for path in package_root.glob("**/*.y*ml"): 120 config_paths.add(path.absolute()) 121 122 return Package( 123 name=package_name, 124 tests=tests, 125 models=models, 126 sources=sources, 127 seeds=seeds, 128 variables=package_variables, 129 macros=macros, 130 materializations=materializations, 131 files=config_paths, 132 on_run_start=on_run_start, 133 on_run_end=on_run_end, 134 )
Loads the specified package.
Returns:
Package containing the configuration found within this package