Edit on GitHub

sqlmesh.dbt.common

  1from __future__ import annotations
  2
  3import re
  4import typing as t
  5from dataclasses import dataclass
  6from pathlib import Path
  7
  8from ruamel.yaml.constructor import DuplicateKeyError
  9from sqlglot.helper import ensure_list
 10
 11from sqlmesh.dbt.util import DBT_VERSION
 12from sqlmesh.core.config.base import BaseConfig, UpdateStrategy
 13from sqlmesh.core.config.common import DBT_PROJECT_FILENAME
 14from sqlmesh.utils import AttributeDict
 15from sqlmesh.utils.conversions import ensure_bool, try_str_to_bool
 16from sqlmesh.utils.errors import ConfigError
 17from sqlmesh.utils.jinja import MacroReference
 18from sqlmesh.utils.pydantic import PydanticModel, field_validator
 19from sqlmesh.utils.yaml import load
 20
 21T = t.TypeVar("T", bound="GeneralConfig")
 22
 23PROJECT_FILENAME = DBT_PROJECT_FILENAME
 24RAW_CODE_KEY = "raw_code" if DBT_VERSION >= (1, 3, 0) else "raw_sql"  # type: ignore
 25
 26JINJA_ONLY = {
 27    "adapter",
 28    "api",
 29    "exceptions",
 30    "flags",
 31    "load_result",
 32    "modules",
 33    "run_query",
 34    "statement",
 35    "store_result",
 36    "target",
 37}
 38
 39
 40def load_yaml(source: str | Path) -> t.Dict:
 41    try:
 42        return load(
 43            source, render_jinja=False, allow_duplicate_keys=True, keep_last_duplicate_key=True
 44        )
 45    except DuplicateKeyError as ex:
 46        raise ConfigError(f"{source}: {ex}" if isinstance(source, Path) else f"{ex}")
 47
 48
 49def parse_meta(v: t.Optional[t.Dict[str, t.Any]]) -> t.Dict[str, t.Any]:
 50    if v is None:
 51        return {}
 52    for key, value in v.items():
 53        if isinstance(value, str):
 54            v[key] = try_str_to_bool(value)
 55
 56    return v
 57
 58
 59class SqlStr(str):
 60    pass
 61
 62
 63sql_str_validator = field_validator("sql", mode="before", check_fields=False)(
 64    lambda v: SqlStr(v) if isinstance(v, str) else v
 65)
 66
 67
 68class DbtConfig(BaseConfig, extra="allow", validate_assignment=True, frozen=False):
 69    pass
 70
 71
 72class GeneralConfig(DbtConfig):
 73    """
 74    General DBT configuration properties for models, sources, seeds, columns, etc.
 75
 76    Args:
 77        description: Description of element
 78        tests: Tests for the element
 79        enabled: When false, the element is ignored
 80        docs: Documentation specific configuration
 81        perist_docs: Persist resource descriptions as column and/or relation comments in the database
 82        tags: List of tags that can be used for element grouping
 83        meta: Dictionary of metadata for the element
 84    """
 85
 86    start: t.Optional[str] = None
 87    description: t.Optional[str] = None
 88    enabled: bool = True
 89    docs: t.Dict[str, t.Any] = {"show": True}
 90    persist_docs: t.Dict[str, t.Any] = {}
 91    tags: t.List[str] = []
 92    meta: t.Dict[str, t.Any] = {}
 93
 94    @field_validator("enabled", mode="before")
 95    @classmethod
 96    def _validate_bool(cls, v: str) -> bool:
 97        return ensure_bool(v)
 98
 99    @field_validator("docs", mode="before")
100    @classmethod
101    def _validate_dict(cls, v: t.Dict[str, t.Any]) -> t.Dict[str, t.Any]:
102        for key, value in v.items():
103            if isinstance(value, str):
104                v[key] = try_str_to_bool(value)
105
106        return v
107
108    @field_validator("persist_docs", mode="before")
109    @classmethod
110    def _validate_persist_docs(cls, v: t.Dict[str, str]) -> t.Dict[str, bool]:
111        return {key: bool(value) for key, value in v.items()}
112
113    @field_validator("tags", mode="before")
114    @classmethod
115    def _validate_list(cls, v: t.Union[str, t.List[str]]) -> t.List[str]:
116        return ensure_list(v)
117
118    @field_validator("meta", mode="before")
119    @classmethod
120    def _validate_meta(cls, v: t.Optional[t.Dict[str, t.Union[str, t.Any]]]) -> t.Dict[str, t.Any]:
121        return parse_meta(v)
122
123    _FIELD_UPDATE_STRATEGY: t.ClassVar[t.Dict[str, UpdateStrategy]] = {
124        **BaseConfig._FIELD_UPDATE_STRATEGY,
125        **{
126            "tests": UpdateStrategy.KEY_UPDATE,
127            "docs": UpdateStrategy.KEY_UPDATE,
128            "persist_docs": UpdateStrategy.KEY_UPDATE,
129            "tags": UpdateStrategy.EXTEND,
130            "meta": UpdateStrategy.KEY_UPDATE,
131        },
132    }
133
134    _SQL_FIELDS: t.ClassVar[t.List[str]] = []
135
136    @property
137    def config_attribute_dict(self) -> AttributeDict[str, t.Any]:
138        return AttributeDict(self.dict(exclude=EXCLUDED_CONFIG_ATTRIBUTE_KEYS))
139
140    def _get_field_value(self, field: str) -> t.Optional[t.Any]:
141        field_val = getattr(self, field, None)
142        return field_val if field_val is not None else self.meta.get(field, None)
143
144    def replace(self, other: T) -> None:
145        """
146        Replace the contents of this instance with the passed in instance.
147
148        Args:
149            other: The instance to apply to this instance
150        """
151        for field in other.fields_set:
152            setattr(self, field, getattr(other, field))
153
154    @property
155    def sqlmesh_config_kwargs(self) -> t.Dict[str, t.Any]:
156        """
157        Create a kwargs dict of all sqlmesh config fields.
158
159        Returns:
160            Kwargs dict of sqlmesh config fields.
161        """
162        kwargs = {}
163        for field in self.sqlmesh_config_fields:
164            field_val = self._get_field_value(field)
165            if field_val is not None:
166                kwargs[field] = field_val
167        return kwargs
168
169    @property
170    def sqlmesh_config_fields(self) -> t.Set[str]:
171        """
172        SQLMesh config fields that can be set in dbt projects.
173
174        Returns:
175            A set of SQLMesh config fields that can be set in dbt projects.
176        """
177        return set()
178
179
180@dataclass
181class ModelAttrs:
182    attrs: t.Set[str]
183    all_attrs: bool = False
184
185
186class Dependencies(PydanticModel):
187    """
188    DBT dependencies for a model, macro, etc.
189
190    Args:
191        macros: The references to macros
192        sources: The "source_name.table_name" for source tables used
193        refs: The table_name for models used
194    """
195
196    macros: t.List[MacroReference] = []
197    sources: t.Set[str] = set()
198    refs: t.Set[str] = set()
199    variables: t.Set[str] = set()
200    model_attrs: ModelAttrs = ModelAttrs(attrs=set())
201
202    has_dynamic_var_names: bool = False
203
204    def union(self, other: Dependencies) -> Dependencies:
205        return Dependencies(
206            macros=list(set(self.macros) | set(other.macros)),
207            sources=self.sources | other.sources,
208            refs=self.refs | other.refs,
209            variables=self.variables | other.variables,
210            model_attrs=ModelAttrs(
211                attrs=self.model_attrs.attrs | other.model_attrs.attrs,
212                all_attrs=self.model_attrs.all_attrs or other.model_attrs.all_attrs,
213            ),
214            has_dynamic_var_names=self.has_dynamic_var_names or other.has_dynamic_var_names,
215        )
216
217    @field_validator("macros", mode="after")
218    @classmethod
219    def _sort_macros(cls, v: t.List[MacroReference]) -> t.List[MacroReference]:
220        return sorted(v, key=lambda x: (x.package or "", x.name))
221
222    def dict(self, *args: t.Any, **kwargs: t.Any) -> t.Dict[str, t.Any]:
223        # See https://github.com/pydantic/pydantic/issues/1090
224        exclude = kwargs.pop("exclude", None) or set()
225
226        out = super().dict(*args, **kwargs, exclude={*exclude, "macros"})
227        if "macros" not in exclude:
228            out["macros"] = [macro.dict() for macro in self.macros]
229
230        return out
231
232
233def extract_jinja_config(input: str) -> t.Tuple[str, str]:
234    def jinja_end(sql: str, start: int) -> int:
235        cursor = start
236        quote = None
237        while cursor < len(sql):
238            if sql[cursor] in ('"', "'"):
239                if quote is None:
240                    quote = sql[cursor]
241                elif quote == sql[cursor]:
242                    quote = None
243            if sql[cursor : cursor + 2] == "}}" and quote is None:
244                return cursor + 2
245            cursor += 1
246        return cursor
247
248    no_config = input
249    only_config = ""
250    matches = re.findall(r"{{\s*config\s*\(", no_config)
251    for match in matches:
252        start = no_config.find(match)
253        if start == -1:
254            continue
255        extracted = no_config[start : jinja_end(no_config, start)]
256        only_config = SqlStr("\n".join([only_config, extracted]) if only_config else extracted)
257        no_config = SqlStr(no_config.replace(extracted, "").strip())
258
259    return (no_config, only_config)
260
261
262EXCLUDED_CONFIG_ATTRIBUTE_KEYS = {
263    "config",
264    "config_call_dict",
265    "checksum",
266    "created_at",
267    "contract",
268    "depends_on",
269    "dependencies",
270    "docs",
271    "metrics",
272    "original_file_path",
273    "packages",
274    "patch_path",
275    "path",
276    "persist_docs",
277    "post_hook",
278    "pre_hook",
279    "raw_code",
280    "refs",
281    "resource_type",
282    "sources",
283    "sql",
284    "tests",
285    "unrendered_config",
286}
PROJECT_FILENAME = 'dbt_project.yml'
RAW_CODE_KEY = 'raw_code'
JINJA_ONLY = {'api', 'flags', 'statement', 'exceptions', 'adapter', 'run_query', 'store_result', 'load_result', 'target', 'modules'}
def load_yaml(source: str | pathlib.Path) -> Dict:
41def load_yaml(source: str | Path) -> t.Dict:
42    try:
43        return load(
44            source, render_jinja=False, allow_duplicate_keys=True, keep_last_duplicate_key=True
45        )
46    except DuplicateKeyError as ex:
47        raise ConfigError(f"{source}: {ex}" if isinstance(source, Path) else f"{ex}")
def parse_meta(v: Optional[Dict[str, Any]]) -> Dict[str, Any]:
50def parse_meta(v: t.Optional[t.Dict[str, t.Any]]) -> t.Dict[str, t.Any]:
51    if v is None:
52        return {}
53    for key, value in v.items():
54        if isinstance(value, str):
55            v[key] = try_str_to_bool(value)
56
57    return v
class SqlStr(builtins.str):
60class SqlStr(str):
61    pass

str(object='') -> str str(bytes_or_buffer[, encoding[, errors]]) -> str

Create a new string object from the given object. If encoding or errors is specified, then the object must expose a data buffer that will be decoded using the given encoding and error handler. Otherwise, returns the result of object.__str__() (if defined) or repr(object). encoding defaults to sys.getdefaultencoding(). errors defaults to 'strict'.

Inherited Members
builtins.str
encode
replace
split
rsplit
join
capitalize
casefold
title
center
count
expandtabs
find
partition
index
ljust
lower
lstrip
rfind
rindex
rjust
rstrip
rpartition
splitlines
strip
swapcase
translate
upper
startswith
endswith
removeprefix
removesuffix
isascii
islower
isupper
istitle
isspace
isdecimal
isdigit
isnumeric
isalpha
isalnum
isidentifier
isprintable
zfill
format
format_map
maketrans
def sql_str_validator(unknown):

Wrap a classmethod, staticmethod, property or unbound function and act as a descriptor that allows us to detect decorated items from the class' attributes.

This class' __get__ returns the wrapped item's __get__ result, which makes it transparent for classmethods and staticmethods.

Attributes:
  • wrapped: The decorator that has to be wrapped.
  • decorator_info: The decorator info.
  • shim: A wrapper function to wrap V1 style function.
class DbtConfig(sqlmesh.core.config.base.BaseConfig):
69class DbtConfig(BaseConfig, extra="allow", validate_assignment=True, frozen=False):
70    pass

Base configuration functionality for configuration classes.

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': 'allow', 'protected_namespaces': (), 'validate_assignment': True, 'frozen': False}

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
sqlmesh.core.config.base.BaseConfig
update_with
sqlmesh.utils.pydantic.PydanticModel
dict
json
copy
fields_set
parse_obj
parse_raw
missing_required_fields
extra_fields
all_fields
all_field_infos
required_fields
class GeneralConfig(DbtConfig):
 73class GeneralConfig(DbtConfig):
 74    """
 75    General DBT configuration properties for models, sources, seeds, columns, etc.
 76
 77    Args:
 78        description: Description of element
 79        tests: Tests for the element
 80        enabled: When false, the element is ignored
 81        docs: Documentation specific configuration
 82        perist_docs: Persist resource descriptions as column and/or relation comments in the database
 83        tags: List of tags that can be used for element grouping
 84        meta: Dictionary of metadata for the element
 85    """
 86
 87    start: t.Optional[str] = None
 88    description: t.Optional[str] = None
 89    enabled: bool = True
 90    docs: t.Dict[str, t.Any] = {"show": True}
 91    persist_docs: t.Dict[str, t.Any] = {}
 92    tags: t.List[str] = []
 93    meta: t.Dict[str, t.Any] = {}
 94
 95    @field_validator("enabled", mode="before")
 96    @classmethod
 97    def _validate_bool(cls, v: str) -> bool:
 98        return ensure_bool(v)
 99
100    @field_validator("docs", mode="before")
101    @classmethod
102    def _validate_dict(cls, v: t.Dict[str, t.Any]) -> t.Dict[str, t.Any]:
103        for key, value in v.items():
104            if isinstance(value, str):
105                v[key] = try_str_to_bool(value)
106
107        return v
108
109    @field_validator("persist_docs", mode="before")
110    @classmethod
111    def _validate_persist_docs(cls, v: t.Dict[str, str]) -> t.Dict[str, bool]:
112        return {key: bool(value) for key, value in v.items()}
113
114    @field_validator("tags", mode="before")
115    @classmethod
116    def _validate_list(cls, v: t.Union[str, t.List[str]]) -> t.List[str]:
117        return ensure_list(v)
118
119    @field_validator("meta", mode="before")
120    @classmethod
121    def _validate_meta(cls, v: t.Optional[t.Dict[str, t.Union[str, t.Any]]]) -> t.Dict[str, t.Any]:
122        return parse_meta(v)
123
124    _FIELD_UPDATE_STRATEGY: t.ClassVar[t.Dict[str, UpdateStrategy]] = {
125        **BaseConfig._FIELD_UPDATE_STRATEGY,
126        **{
127            "tests": UpdateStrategy.KEY_UPDATE,
128            "docs": UpdateStrategy.KEY_UPDATE,
129            "persist_docs": UpdateStrategy.KEY_UPDATE,
130            "tags": UpdateStrategy.EXTEND,
131            "meta": UpdateStrategy.KEY_UPDATE,
132        },
133    }
134
135    _SQL_FIELDS: t.ClassVar[t.List[str]] = []
136
137    @property
138    def config_attribute_dict(self) -> AttributeDict[str, t.Any]:
139        return AttributeDict(self.dict(exclude=EXCLUDED_CONFIG_ATTRIBUTE_KEYS))
140
141    def _get_field_value(self, field: str) -> t.Optional[t.Any]:
142        field_val = getattr(self, field, None)
143        return field_val if field_val is not None else self.meta.get(field, None)
144
145    def replace(self, other: T) -> None:
146        """
147        Replace the contents of this instance with the passed in instance.
148
149        Args:
150            other: The instance to apply to this instance
151        """
152        for field in other.fields_set:
153            setattr(self, field, getattr(other, field))
154
155    @property
156    def sqlmesh_config_kwargs(self) -> t.Dict[str, t.Any]:
157        """
158        Create a kwargs dict of all sqlmesh config fields.
159
160        Returns:
161            Kwargs dict of sqlmesh config fields.
162        """
163        kwargs = {}
164        for field in self.sqlmesh_config_fields:
165            field_val = self._get_field_value(field)
166            if field_val is not None:
167                kwargs[field] = field_val
168        return kwargs
169
170    @property
171    def sqlmesh_config_fields(self) -> t.Set[str]:
172        """
173        SQLMesh config fields that can be set in dbt projects.
174
175        Returns:
176            A set of SQLMesh config fields that can be set in dbt projects.
177        """
178        return set()

General DBT configuration properties for models, sources, seeds, columns, etc.

Arguments:
  • description: Description of element
  • tests: Tests for the element
  • enabled: When false, the element is ignored
  • docs: Documentation specific configuration
  • perist_docs: Persist resource descriptions as column and/or relation comments in the database
  • tags: List of tags that can be used for element grouping
  • meta: Dictionary of metadata for the element
start: Optional[str]
description: Optional[str]
enabled: bool
docs: Dict[str, Any]
persist_docs: Dict[str, Any]
tags: List[str]
meta: Dict[str, Any]
config_attribute_dict: sqlmesh.utils.AttributeDict[str, typing.Any]
137    @property
138    def config_attribute_dict(self) -> AttributeDict[str, t.Any]:
139        return AttributeDict(self.dict(exclude=EXCLUDED_CONFIG_ATTRIBUTE_KEYS))
def replace(self, other: ~T) -> None:
145    def replace(self, other: T) -> None:
146        """
147        Replace the contents of this instance with the passed in instance.
148
149        Args:
150            other: The instance to apply to this instance
151        """
152        for field in other.fields_set:
153            setattr(self, field, getattr(other, field))

Replace the contents of this instance with the passed in instance.

Arguments:
  • other: The instance to apply to this instance
sqlmesh_config_kwargs: Dict[str, Any]
155    @property
156    def sqlmesh_config_kwargs(self) -> t.Dict[str, t.Any]:
157        """
158        Create a kwargs dict of all sqlmesh config fields.
159
160        Returns:
161            Kwargs dict of sqlmesh config fields.
162        """
163        kwargs = {}
164        for field in self.sqlmesh_config_fields:
165            field_val = self._get_field_value(field)
166            if field_val is not None:
167                kwargs[field] = field_val
168        return kwargs

Create a kwargs dict of all sqlmesh config fields.

Returns:

Kwargs dict of sqlmesh config fields.

sqlmesh_config_fields: Set[str]
170    @property
171    def sqlmesh_config_fields(self) -> t.Set[str]:
172        """
173        SQLMesh config fields that can be set in dbt projects.
174
175        Returns:
176            A set of SQLMesh config fields that can be set in dbt projects.
177        """
178        return set()

SQLMesh config fields that can be set in dbt projects.

Returns:

A set of SQLMesh config fields that can be set in dbt projects.

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': 'allow', 'protected_namespaces': (), 'validate_assignment': True, 'frozen': False}

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
sqlmesh.core.config.base.BaseConfig
update_with
sqlmesh.utils.pydantic.PydanticModel
dict
json
copy
fields_set
parse_obj
parse_raw
missing_required_fields
extra_fields
all_fields
all_field_infos
required_fields
@dataclass
class ModelAttrs:
181@dataclass
182class ModelAttrs:
183    attrs: t.Set[str]
184    all_attrs: bool = False
ModelAttrs(attrs: Set[str], all_attrs: bool = False)
attrs: Set[str]
all_attrs: bool = False
class Dependencies(sqlmesh.utils.pydantic.PydanticModel):
187class Dependencies(PydanticModel):
188    """
189    DBT dependencies for a model, macro, etc.
190
191    Args:
192        macros: The references to macros
193        sources: The "source_name.table_name" for source tables used
194        refs: The table_name for models used
195    """
196
197    macros: t.List[MacroReference] = []
198    sources: t.Set[str] = set()
199    refs: t.Set[str] = set()
200    variables: t.Set[str] = set()
201    model_attrs: ModelAttrs = ModelAttrs(attrs=set())
202
203    has_dynamic_var_names: bool = False
204
205    def union(self, other: Dependencies) -> Dependencies:
206        return Dependencies(
207            macros=list(set(self.macros) | set(other.macros)),
208            sources=self.sources | other.sources,
209            refs=self.refs | other.refs,
210            variables=self.variables | other.variables,
211            model_attrs=ModelAttrs(
212                attrs=self.model_attrs.attrs | other.model_attrs.attrs,
213                all_attrs=self.model_attrs.all_attrs or other.model_attrs.all_attrs,
214            ),
215            has_dynamic_var_names=self.has_dynamic_var_names or other.has_dynamic_var_names,
216        )
217
218    @field_validator("macros", mode="after")
219    @classmethod
220    def _sort_macros(cls, v: t.List[MacroReference]) -> t.List[MacroReference]:
221        return sorted(v, key=lambda x: (x.package or "", x.name))
222
223    def dict(self, *args: t.Any, **kwargs: t.Any) -> t.Dict[str, t.Any]:
224        # See https://github.com/pydantic/pydantic/issues/1090
225        exclude = kwargs.pop("exclude", None) or set()
226
227        out = super().dict(*args, **kwargs, exclude={*exclude, "macros"})
228        if "macros" not in exclude:
229            out["macros"] = [macro.dict() for macro in self.macros]
230
231        return out

DBT dependencies for a model, macro, etc.

Arguments:
  • macros: The references to macros
  • sources: The "source_name.table_name" for source tables used
  • refs: The table_name for models used
sources: Set[str]
refs: Set[str]
variables: Set[str]
model_attrs: ModelAttrs
has_dynamic_var_names: bool
def union( self, other: Dependencies) -> Dependencies:
205    def union(self, other: Dependencies) -> Dependencies:
206        return Dependencies(
207            macros=list(set(self.macros) | set(other.macros)),
208            sources=self.sources | other.sources,
209            refs=self.refs | other.refs,
210            variables=self.variables | other.variables,
211            model_attrs=ModelAttrs(
212                attrs=self.model_attrs.attrs | other.model_attrs.attrs,
213                all_attrs=self.model_attrs.all_attrs or other.model_attrs.all_attrs,
214            ),
215            has_dynamic_var_names=self.has_dynamic_var_names or other.has_dynamic_var_names,
216        )
def dict(self, *args: Any, **kwargs: Any) -> Dict[str, Any]:
223    def dict(self, *args: t.Any, **kwargs: t.Any) -> t.Dict[str, t.Any]:
224        # See https://github.com/pydantic/pydantic/issues/1090
225        exclude = kwargs.pop("exclude", None) or set()
226
227        out = super().dict(*args, **kwargs, exclude={*exclude, "macros"})
228        if "macros" not in exclude:
229            out["macros"] = [macro.dict() for macro in self.macros]
230
231        return out
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
sqlmesh.utils.pydantic.PydanticModel
json
copy
fields_set
parse_obj
parse_raw
missing_required_fields
extra_fields
all_fields
all_field_infos
required_fields
def extract_jinja_config(input: str) -> Tuple[str, str]:
234def extract_jinja_config(input: str) -> t.Tuple[str, str]:
235    def jinja_end(sql: str, start: int) -> int:
236        cursor = start
237        quote = None
238        while cursor < len(sql):
239            if sql[cursor] in ('"', "'"):
240                if quote is None:
241                    quote = sql[cursor]
242                elif quote == sql[cursor]:
243                    quote = None
244            if sql[cursor : cursor + 2] == "}}" and quote is None:
245                return cursor + 2
246            cursor += 1
247        return cursor
248
249    no_config = input
250    only_config = ""
251    matches = re.findall(r"{{\s*config\s*\(", no_config)
252    for match in matches:
253        start = no_config.find(match)
254        if start == -1:
255            continue
256        extracted = no_config[start : jinja_end(no_config, start)]
257        only_config = SqlStr("\n".join([only_config, extracted]) if only_config else extracted)
258        no_config = SqlStr(no_config.replace(extracted, "").strip())
259
260    return (no_config, only_config)
EXCLUDED_CONFIG_ATTRIBUTE_KEYS = {'tests', 'unrendered_config', 'config', 'dependencies', 'config_call_dict', 'refs', 'pre_hook', 'docs', 'sql', 'raw_code', 'resource_type', 'path', 'original_file_path', 'metrics', 'sources', 'patch_path', 'depends_on', 'checksum', 'created_at', 'packages', 'contract', 'persist_docs', 'post_hook'}