Edit on GitHub

sqlmesh.core.model.kind

   1from __future__ import annotations
   2
   3import typing as t
   4from enum import Enum
   5from typing_extensions import Self
   6
   7from pydantic import Field
   8from sqlglot import exp
   9from sqlglot.optimizer.normalize_identifiers import normalize_identifiers
  10from sqlglot.optimizer.qualify_columns import quote_identifiers
  11from sqlglot.optimizer.simplify import gen
  12from sqlglot.time import format_time
  13
  14from sqlmesh.core import dialect as d
  15from sqlmesh.core.model.common import (
  16    parse_properties,
  17    properties_validator,
  18    validate_extra_and_required_fields,
  19)
  20from sqlmesh.core.model.seed import CsvSettings
  21from sqlmesh.utils.errors import ConfigError
  22from sqlmesh.utils.pydantic import (
  23    PydanticModel,
  24    SQLGlotBool,
  25    SQLGlotColumn,
  26    SQLGlotListOfFieldsOrStar,
  27    SQLGlotListOfFields,
  28    SQLGlotPositiveInt,
  29    SQLGlotString,
  30    SQLGlotCron,
  31    ValidationInfo,
  32    column_validator,
  33    field_validator,
  34    get_dialect,
  35    validate_string,
  36    validate_expression,
  37)
  38
  39
  40if t.TYPE_CHECKING:
  41    from sqlmesh.core._typing import CustomMaterializationProperties
  42
  43    MODEL_KIND = t.TypeVar("MODEL_KIND", bound="_ModelKind")
  44
  45
  46class ModelKindMixin:
  47    @property
  48    def model_kind_name(self) -> t.Optional[ModelKindName]:
  49        """Returns the model kind name."""
  50        raise NotImplementedError
  51
  52    @property
  53    def is_incremental_by_time_range(self) -> bool:
  54        return self.model_kind_name == ModelKindName.INCREMENTAL_BY_TIME_RANGE
  55
  56    @property
  57    def is_incremental_by_unique_key(self) -> bool:
  58        return self.model_kind_name == ModelKindName.INCREMENTAL_BY_UNIQUE_KEY
  59
  60    @property
  61    def is_incremental_by_partition(self) -> bool:
  62        return self.model_kind_name == ModelKindName.INCREMENTAL_BY_PARTITION
  63
  64    @property
  65    def is_incremental_unmanaged(self) -> bool:
  66        return self.model_kind_name == ModelKindName.INCREMENTAL_UNMANAGED
  67
  68    @property
  69    def is_incremental(self) -> bool:
  70        return (
  71            self.is_incremental_by_time_range
  72            or self.is_incremental_by_unique_key
  73            or self.is_incremental_by_partition
  74            or self.is_incremental_unmanaged
  75            or self.is_scd_type_2
  76        )
  77
  78    @property
  79    def is_full(self) -> bool:
  80        return self.model_kind_name == ModelKindName.FULL
  81
  82    @property
  83    def is_view(self) -> bool:
  84        return self.model_kind_name == ModelKindName.VIEW
  85
  86    @property
  87    def is_embedded(self) -> bool:
  88        return self.model_kind_name == ModelKindName.EMBEDDED
  89
  90    @property
  91    def is_seed(self) -> bool:
  92        return self.model_kind_name == ModelKindName.SEED
  93
  94    @property
  95    def is_external(self) -> bool:
  96        return self.model_kind_name == ModelKindName.EXTERNAL
  97
  98    @property
  99    def is_scd_type_2(self) -> bool:
 100        return self.model_kind_name in {
 101            ModelKindName.SCD_TYPE_2,
 102            ModelKindName.SCD_TYPE_2_BY_TIME,
 103            ModelKindName.SCD_TYPE_2_BY_COLUMN,
 104        }
 105
 106    @property
 107    def is_scd_type_2_by_time(self) -> bool:
 108        return self.model_kind_name in {ModelKindName.SCD_TYPE_2, ModelKindName.SCD_TYPE_2_BY_TIME}
 109
 110    @property
 111    def is_scd_type_2_by_column(self) -> bool:
 112        return self.model_kind_name == ModelKindName.SCD_TYPE_2_BY_COLUMN
 113
 114    @property
 115    def is_custom(self) -> bool:
 116        return self.model_kind_name == ModelKindName.CUSTOM
 117
 118    @property
 119    def is_managed(self) -> bool:
 120        return self.model_kind_name == ModelKindName.MANAGED
 121
 122    @property
 123    def is_dbt_custom(self) -> bool:
 124        return self.model_kind_name == ModelKindName.DBT_CUSTOM
 125
 126    @property
 127    def is_symbolic(self) -> bool:
 128        """A symbolic model is one that doesn't execute at all."""
 129        return self.model_kind_name in (ModelKindName.EMBEDDED, ModelKindName.EXTERNAL)
 130
 131    @property
 132    def is_materialized(self) -> bool:
 133        return self.model_kind_name is not None and not (self.is_symbolic or self.is_view)
 134
 135    @property
 136    def only_execution_time(self) -> bool:
 137        """Whether or not this model only cares about execution time to render."""
 138        return self.is_view or self.is_full
 139
 140    @property
 141    def full_history_restatement_only(self) -> bool:
 142        """Whether or not this model only supports restatement of full history."""
 143        return (
 144            self.is_incremental_unmanaged
 145            or self.is_incremental_by_unique_key
 146            or self.is_incremental_by_partition
 147            or self.is_scd_type_2
 148            or self.is_managed
 149            or self.is_full
 150            or self.is_view
 151        )
 152
 153    @property
 154    def supports_python_models(self) -> bool:
 155        return True
 156
 157    @property
 158    def supports_grants(self) -> bool:
 159        """Whether this model kind supports grants configuration."""
 160        return self.is_materialized or self.is_view
 161
 162
 163class ModelKindName(str, ModelKindMixin, Enum):
 164    """The kind of model, determining how this data is computed and stored in the warehouse."""
 165
 166    INCREMENTAL_BY_TIME_RANGE = "INCREMENTAL_BY_TIME_RANGE"
 167    INCREMENTAL_BY_UNIQUE_KEY = "INCREMENTAL_BY_UNIQUE_KEY"
 168    INCREMENTAL_BY_PARTITION = "INCREMENTAL_BY_PARTITION"
 169    INCREMENTAL_UNMANAGED = "INCREMENTAL_UNMANAGED"
 170    FULL = "FULL"
 171    # Legacy alias to SCD Type 2 By Time
 172    # Only used for Parsing and mapping name to SCD Type 2 By Time
 173    SCD_TYPE_2 = "SCD_TYPE_2"
 174    SCD_TYPE_2_BY_TIME = "SCD_TYPE_2_BY_TIME"
 175    SCD_TYPE_2_BY_COLUMN = "SCD_TYPE_2_BY_COLUMN"
 176    VIEW = "VIEW"
 177    EMBEDDED = "EMBEDDED"
 178    SEED = "SEED"
 179    EXTERNAL = "EXTERNAL"
 180    CUSTOM = "CUSTOM"
 181    MANAGED = "MANAGED"
 182    DBT_CUSTOM = "DBT_CUSTOM"
 183
 184    @property
 185    def model_kind_name(self) -> t.Optional[ModelKindName]:
 186        return self
 187
 188    def __str__(self) -> str:
 189        return self.name
 190
 191    def __repr__(self) -> str:
 192        return str(self)
 193
 194
 195class OnDestructiveChange(str, Enum):
 196    """What should happen when a forward-only model change requires a destructive schema change."""
 197
 198    ERROR = "ERROR"
 199    WARN = "WARN"
 200    ALLOW = "ALLOW"
 201    IGNORE = "IGNORE"
 202
 203    @property
 204    def is_error(self) -> bool:
 205        return self == OnDestructiveChange.ERROR
 206
 207    @property
 208    def is_warn(self) -> bool:
 209        return self == OnDestructiveChange.WARN
 210
 211    @property
 212    def is_allow(self) -> bool:
 213        return self == OnDestructiveChange.ALLOW
 214
 215    @property
 216    def is_ignore(self) -> bool:
 217        return self == OnDestructiveChange.IGNORE
 218
 219
 220class OnAdditiveChange(str, Enum):
 221    """What should happen when a forward-only model change requires an additive schema change."""
 222
 223    ERROR = "ERROR"
 224    WARN = "WARN"
 225    ALLOW = "ALLOW"
 226    IGNORE = "IGNORE"
 227
 228    @property
 229    def is_error(self) -> bool:
 230        return self == OnAdditiveChange.ERROR
 231
 232    @property
 233    def is_warn(self) -> bool:
 234        return self == OnAdditiveChange.WARN
 235
 236    @property
 237    def is_allow(self) -> bool:
 238        return self == OnAdditiveChange.ALLOW
 239
 240    @property
 241    def is_ignore(self) -> bool:
 242        return self == OnAdditiveChange.IGNORE
 243
 244
 245def _on_destructive_change_validator(
 246    cls: t.Type, v: t.Union[OnDestructiveChange, str, exp.Identifier]
 247) -> t.Any:
 248    if v and not isinstance(v, OnDestructiveChange):
 249        return OnDestructiveChange(
 250            v.this.upper() if isinstance(v, (exp.Identifier, exp.Literal)) else v.upper()
 251        )
 252    return v
 253
 254
 255def _on_additive_change_validator(
 256    cls: t.Type, v: t.Union[OnAdditiveChange, str, exp.Identifier]
 257) -> t.Any:
 258    if v and not isinstance(v, OnAdditiveChange):
 259        return OnAdditiveChange(
 260            v.this.upper() if isinstance(v, (exp.Identifier, exp.Literal)) else v.upper()
 261        )
 262    return v
 263
 264
 265on_additive_change_validator = field_validator("on_additive_change", mode="before")(
 266    _on_additive_change_validator
 267)
 268
 269on_destructive_change_validator = field_validator("on_destructive_change", mode="before")(
 270    _on_destructive_change_validator
 271)
 272
 273
 274class _ModelKind(PydanticModel, ModelKindMixin):
 275    name: ModelKindName
 276
 277    @property
 278    def model_kind_name(self) -> t.Optional[ModelKindName]:
 279        return self.name
 280
 281    def to_expression(
 282        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
 283    ) -> d.ModelKind:
 284        kwargs["expressions"] = expressions
 285        return d.ModelKind(this=self.name.value.upper(), **kwargs)
 286
 287    @property
 288    def data_hash_values(self) -> t.List[t.Optional[str]]:
 289        return [self.name.value]
 290
 291    @property
 292    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
 293        return []
 294
 295
 296class TimeColumn(PydanticModel):
 297    column: exp.Expr
 298    format: t.Optional[str] = None
 299
 300    @classmethod
 301    def validator(cls) -> classmethod:
 302        def _time_column_validator(v: t.Any, info: ValidationInfo) -> TimeColumn:
 303            return TimeColumn.create(v, get_dialect(info.data))
 304
 305        return field_validator("time_column", mode="before")(_time_column_validator)
 306
 307    @field_validator("column", mode="before")
 308    @classmethod
 309    def _column_validator(cls, v: t.Union[str, exp.Expr]) -> exp.Expr:
 310        if not v:
 311            raise ConfigError("Time Column cannot be empty.")
 312        if isinstance(v, str):
 313            return exp.to_column(v)
 314        return v
 315
 316    @property
 317    def expression(self) -> exp.Expr:
 318        """Convert this pydantic model into a time_column SQLGlot expression."""
 319        if not self.format:
 320            return self.column
 321
 322        return exp.Tuple(expressions=[self.column, exp.Literal.string(self.format)])
 323
 324    def to_expression(self, dialect: str) -> exp.Expr:
 325        """Convert this pydantic model into a time_column SQLGlot expression."""
 326        if not self.format:
 327            return self.column
 328
 329        return exp.Tuple(
 330            expressions=[
 331                self.column,
 332                exp.Literal.string(
 333                    format_time(self.format, d.Dialect.get_or_raise(dialect).INVERSE_TIME_MAPPING)
 334                ),
 335            ]
 336        )
 337
 338    def to_property(self, dialect: str = "") -> exp.Property:
 339        return exp.Property(this="time_column", value=self.to_expression(dialect))
 340
 341    @classmethod
 342    def create(cls, v: t.Any, dialect: str) -> Self:
 343        if isinstance(v, exp.Tuple):
 344            if not v.expressions:
 345                raise ConfigError("Time Column cannot be empty.")
 346            column_expr = v.expressions[0]
 347            column = (
 348                exp.column(column_expr) if isinstance(column_expr, exp.Identifier) else column_expr
 349            )
 350            format = v.expressions[1].name if len(v.expressions) > 1 else None
 351        elif isinstance(v, exp.Expr):
 352            column = exp.column(v) if isinstance(v, exp.Identifier) else v
 353            format = None
 354        elif isinstance(v, str):
 355            column = d.parse_one(v, dialect=dialect)
 356            column.meta.pop("sql")
 357            format = None
 358        elif isinstance(v, dict):
 359            column_raw = v["column"]
 360            column = (
 361                d.parse_one(column_raw, dialect=dialect)
 362                if isinstance(column_raw, str)
 363                else column_raw
 364            )
 365            format = v.get("format")
 366        elif isinstance(v, TimeColumn):
 367            column = v.column
 368            format = v.format
 369        else:
 370            raise ConfigError(f"Invalid time_column: '{v}'.")
 371
 372        column = quote_identifiers(normalize_identifiers(column, dialect=dialect), dialect=dialect)
 373        column.meta["dialect"] = dialect
 374
 375        return cls(column=column, format=format)
 376
 377
 378def _kind_dialect_validator(cls: t.Type, v: t.Optional[str]) -> str:
 379    if v is None:
 380        return get_dialect({})
 381    return v
 382
 383
 384kind_dialect_validator = field_validator("dialect", mode="before")(_kind_dialect_validator)
 385
 386
 387class _Incremental(_ModelKind):
 388    on_destructive_change: OnDestructiveChange = OnDestructiveChange.ERROR
 389    on_additive_change: OnAdditiveChange = OnAdditiveChange.ALLOW
 390    auto_restatement_cron: t.Optional[SQLGlotCron] = None
 391
 392    _on_destructive_change_validator = on_destructive_change_validator
 393    _on_additive_change_validator = on_additive_change_validator
 394
 395    @property
 396    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
 397        return [
 398            *super().metadata_hash_values,
 399            str(self.on_destructive_change),
 400            str(self.on_additive_change),
 401            self.auto_restatement_cron,
 402        ]
 403
 404    def to_expression(
 405        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
 406    ) -> d.ModelKind:
 407        return super().to_expression(
 408            expressions=[
 409                *(expressions or []),
 410                *_properties(
 411                    {
 412                        "on_destructive_change": self.on_destructive_change.value,
 413                        "on_additive_change": self.on_additive_change.value,
 414                        "auto_restatement_cron": self.auto_restatement_cron,
 415                    }
 416                ),
 417            ],
 418        )
 419
 420
 421class _IncrementalBy(_Incremental):
 422    dialect: t.Optional[str] = Field(None, validate_default=True)
 423    batch_size: t.Optional[SQLGlotPositiveInt] = None
 424    batch_concurrency: t.Optional[SQLGlotPositiveInt] = None
 425    lookback: t.Optional[SQLGlotPositiveInt] = None
 426    forward_only: SQLGlotBool = False
 427    disable_restatement: SQLGlotBool = False
 428
 429    _dialect_validator = kind_dialect_validator
 430
 431    @property
 432    def data_hash_values(self) -> t.List[t.Optional[str]]:
 433        return [
 434            *super().data_hash_values,
 435            self.dialect,
 436            str(self.lookback) if self.lookback is not None else None,
 437        ]
 438
 439    @property
 440    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
 441        return [
 442            *super().metadata_hash_values,
 443            str(self.batch_size) if self.batch_size is not None else None,
 444            str(self.forward_only),
 445            str(self.disable_restatement),
 446        ]
 447
 448    def to_expression(
 449        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
 450    ) -> d.ModelKind:
 451        return super().to_expression(
 452            expressions=[
 453                *(expressions or []),
 454                *_properties(
 455                    {
 456                        "batch_size": self.batch_size,
 457                        "batch_concurrency": self.batch_concurrency,
 458                        "lookback": self.lookback,
 459                        "forward_only": self.forward_only,
 460                        "disable_restatement": self.disable_restatement,
 461                    }
 462                ),
 463            ],
 464        )
 465
 466
 467class IncrementalByTimeRangeKind(_IncrementalBy):
 468    name: t.Literal[ModelKindName.INCREMENTAL_BY_TIME_RANGE] = (
 469        ModelKindName.INCREMENTAL_BY_TIME_RANGE
 470    )
 471    time_column: TimeColumn
 472    auto_restatement_intervals: t.Optional[SQLGlotPositiveInt] = None
 473    partition_by_time_column: SQLGlotBool = True
 474
 475    _time_column_validator = TimeColumn.validator()
 476
 477    def to_expression(
 478        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
 479    ) -> d.ModelKind:
 480        return super().to_expression(
 481            expressions=[
 482                *(expressions or []),
 483                self.time_column.to_property(kwargs.get("dialect") or ""),
 484                *_properties(
 485                    {
 486                        "partition_by_time_column": self.partition_by_time_column,
 487                    }
 488                ),
 489                *(
 490                    [_property("auto_restatement_intervals", self.auto_restatement_intervals)]
 491                    if self.auto_restatement_intervals is not None
 492                    else []
 493                ),
 494            ]
 495        )
 496
 497    @property
 498    def data_hash_values(self) -> t.List[t.Optional[str]]:
 499        return [*super().data_hash_values, gen(self.time_column.column), self.time_column.format]
 500
 501    @property
 502    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
 503        return [
 504            *super().metadata_hash_values,
 505            str(self.partition_by_time_column),
 506            str(self.auto_restatement_intervals)
 507            if self.auto_restatement_intervals is not None
 508            else None,
 509        ]
 510
 511
 512class IncrementalByUniqueKeyKind(_IncrementalBy):
 513    name: t.Literal[ModelKindName.INCREMENTAL_BY_UNIQUE_KEY] = (
 514        ModelKindName.INCREMENTAL_BY_UNIQUE_KEY
 515    )
 516    unique_key: SQLGlotListOfFields
 517    when_matched: t.Optional[exp.Whens] = None
 518    merge_filter: t.Optional[exp.Expr] = None
 519    batch_concurrency: t.Literal[1] = 1
 520
 521    @field_validator("when_matched", mode="before")
 522    def _when_matched_validator(
 523        cls,
 524        v: t.Optional[t.Union[str, list, exp.Whens]],
 525        info: ValidationInfo,
 526    ) -> t.Optional[exp.Whens]:
 527        if v is None:
 528            return v
 529        if isinstance(v, list):
 530            v = " ".join(v)
 531
 532        dialect = get_dialect(info.data)
 533
 534        if isinstance(v, str):
 535            # Whens wrap the WHEN clauses, but the parentheses aren't parsed by sqlglot
 536            v = v.strip()
 537            if v.startswith("("):
 538                v = v[1:-1]
 539
 540            v = t.cast(exp.Whens, d.parse_one(v, into=exp.Whens, dialect=dialect))
 541
 542        v = validate_expression(v, dialect=dialect)
 543        return t.cast(exp.Whens, v.transform(d.replace_merge_table_aliases, dialect=dialect))
 544
 545    @field_validator("merge_filter", mode="before")
 546    def _merge_filter_validator(
 547        cls,
 548        v: t.Optional[exp.Expr],
 549        info: ValidationInfo,
 550    ) -> t.Optional[exp.Expr]:
 551        if v is None:
 552            return v
 553
 554        dialect = get_dialect(info.data)
 555
 556        if isinstance(v, str):
 557            v = v.strip()
 558            v = d.parse_one(v, dialect=dialect)
 559
 560        v = validate_expression(v, dialect=dialect)
 561        return v.transform(d.replace_merge_table_aliases, dialect=dialect)
 562
 563    @property
 564    def data_hash_values(self) -> t.List[t.Optional[str]]:
 565        return [
 566            *super().data_hash_values,
 567            *(gen(k) for k in self.unique_key),
 568            gen(self.when_matched) if self.when_matched is not None else None,
 569            gen(self.merge_filter) if self.merge_filter is not None else None,
 570        ]
 571
 572    def to_expression(
 573        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
 574    ) -> d.ModelKind:
 575        return super().to_expression(
 576            expressions=[
 577                *(expressions or []),
 578                *_properties(
 579                    {
 580                        "unique_key": exp.Tuple(expressions=self.unique_key),
 581                        "when_matched": self.when_matched,
 582                        "merge_filter": self.merge_filter,
 583                    }
 584                ),
 585            ],
 586        )
 587
 588
 589class IncrementalByPartitionKind(_Incremental):
 590    name: t.Literal[ModelKindName.INCREMENTAL_BY_PARTITION] = ModelKindName.INCREMENTAL_BY_PARTITION
 591    forward_only: t.Literal[True] = True
 592    disable_restatement: SQLGlotBool = False
 593
 594    @field_validator("forward_only", mode="before")
 595    def _forward_only_validator(cls, v: t.Union[bool, exp.Expr]) -> t.Literal[True]:
 596        if v is not True:
 597            raise ConfigError(
 598                "Do not specify the `forward_only` configuration key - INCREMENTAL_BY_PARTITION models are always forward_only."
 599            )
 600        return v
 601
 602    @property
 603    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
 604        return [
 605            *super().metadata_hash_values,
 606            str(self.forward_only),
 607            str(self.disable_restatement),
 608        ]
 609
 610    def to_expression(
 611        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
 612    ) -> d.ModelKind:
 613        return super().to_expression(
 614            expressions=[
 615                *(expressions or []),
 616                *_properties(
 617                    {
 618                        "forward_only": self.forward_only,
 619                        "disable_restatement": self.disable_restatement,
 620                    }
 621                ),
 622            ],
 623        )
 624
 625
 626class IncrementalUnmanagedKind(_Incremental):
 627    name: t.Literal[ModelKindName.INCREMENTAL_UNMANAGED] = ModelKindName.INCREMENTAL_UNMANAGED
 628    insert_overwrite: SQLGlotBool = False
 629    forward_only: SQLGlotBool = True
 630    disable_restatement: SQLGlotBool = True
 631
 632    @property
 633    def data_hash_values(self) -> t.List[t.Optional[str]]:
 634        return [*super().data_hash_values, str(self.insert_overwrite)]
 635
 636    @property
 637    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
 638        return [
 639            *super().metadata_hash_values,
 640            str(self.forward_only),
 641            str(self.disable_restatement),
 642        ]
 643
 644    def to_expression(
 645        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
 646    ) -> d.ModelKind:
 647        return super().to_expression(
 648            expressions=[
 649                *(expressions or []),
 650                *_properties(
 651                    {
 652                        "insert_overwrite": self.insert_overwrite,
 653                        "forward_only": self.forward_only,
 654                        "disable_restatement": self.disable_restatement,
 655                    }
 656                ),
 657            ],
 658        )
 659
 660
 661class ViewKind(_ModelKind):
 662    name: t.Literal[ModelKindName.VIEW] = ModelKindName.VIEW
 663    materialized: SQLGlotBool = False
 664
 665    @property
 666    def data_hash_values(self) -> t.List[t.Optional[str]]:
 667        return [*super().data_hash_values, str(self.materialized)]
 668
 669    @property
 670    def supports_python_models(self) -> bool:
 671        return False
 672
 673    def to_expression(
 674        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
 675    ) -> d.ModelKind:
 676        return super().to_expression(
 677            expressions=[
 678                *(expressions or []),
 679                _property("materialized", self.materialized),
 680            ],
 681        )
 682
 683
 684class SeedKind(_ModelKind):
 685    name: t.Literal[ModelKindName.SEED] = ModelKindName.SEED
 686    path: SQLGlotString
 687    batch_size: SQLGlotPositiveInt = 1000
 688    csv_settings: t.Optional[CsvSettings] = None
 689
 690    @field_validator("csv_settings", mode="before")
 691    @classmethod
 692    def _parse_csv_settings(cls, v: t.Any) -> t.Optional[CsvSettings]:
 693        if v is None or isinstance(v, CsvSettings):
 694            return v
 695        if isinstance(v, exp.Expr):
 696            tuple_exp = parse_properties(cls, v, None)
 697            if not tuple_exp:
 698                return None
 699            return CsvSettings(**{e.left.name: e.right for e in tuple_exp.expressions})
 700        if isinstance(v, dict):
 701            return CsvSettings(**v)
 702        return v
 703
 704    def to_expression(
 705        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
 706    ) -> d.ModelKind:
 707        """Convert the seed kind into a SQLGlot expression."""
 708        return super().to_expression(
 709            expressions=[
 710                *(expressions or []),
 711                *_properties(
 712                    {
 713                        "path": exp.Literal.string(self.path),
 714                        "batch_size": self.batch_size,
 715                    }
 716                ),
 717            ],
 718        )
 719
 720    @property
 721    def data_hash_values(self) -> t.List[t.Optional[str]]:
 722        csv_setting_values = (self.csv_settings or CsvSettings()).dict().values()
 723        return [
 724            *super().data_hash_values,
 725            *(v if isinstance(v, (str, type(None))) else str(v) for v in csv_setting_values),
 726        ]
 727
 728    @property
 729    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
 730        return [*super().metadata_hash_values, str(self.batch_size)]
 731
 732    @property
 733    def supports_python_models(self) -> bool:
 734        return False
 735
 736
 737class FullKind(_ModelKind):
 738    name: t.Literal[ModelKindName.FULL] = ModelKindName.FULL
 739
 740
 741class _SCDType2Kind(_Incremental):
 742    dialect: t.Optional[str] = Field(None, validate_default=True)
 743    unique_key: SQLGlotListOfFields
 744    valid_from_name: SQLGlotColumn = Field(exp.column("valid_from"), validate_default=True)
 745    valid_to_name: SQLGlotColumn = Field(exp.column("valid_to"), validate_default=True)
 746    invalidate_hard_deletes: SQLGlotBool = False
 747    time_data_type: exp.DataType = Field(exp.DataType.build("TIMESTAMP"), validate_default=True)
 748    batch_size: t.Optional[SQLGlotPositiveInt] = None
 749
 750    forward_only: SQLGlotBool = True
 751    disable_restatement: SQLGlotBool = True
 752
 753    _dialect_validator = kind_dialect_validator
 754
 755    _always_validate_column = field_validator("valid_from_name", "valid_to_name", mode="before")(
 756        column_validator
 757    )
 758
 759    @field_validator("time_data_type", mode="before")
 760    @classmethod
 761    def _time_data_type_validator(cls, v: t.Union[str, exp.Expr], values: t.Any) -> exp.Expr:
 762        if isinstance(v, exp.Expr) and not isinstance(v, exp.DataType):
 763            v = v.name
 764        dialect = get_dialect(values)
 765        data_type = exp.DataType.build(v, dialect=dialect)
 766        # Clear meta["sql"] (set by our parser extension) so the pydantic encoder
 767        # uses dialect-aware rendering: e.sql(dialect=meta["dialect"]). Without this,
 768        # the raw SQL text takes priority, which can be wrong for dialect-normalized
 769        # types (e.g., default "TIMESTAMP" should render as "DATETIME" in BigQuery).
 770        data_type.meta.pop("sql", None)
 771        data_type.meta["dialect"] = dialect
 772        return data_type
 773
 774    @property
 775    def managed_columns(self) -> t.Dict[str, exp.DataType]:
 776        return {
 777            self.valid_from_name.name: self.time_data_type,
 778            self.valid_to_name.name: self.time_data_type,
 779        }
 780
 781    @property
 782    def data_hash_values(self) -> t.List[t.Optional[str]]:
 783        return [
 784            *super().data_hash_values,
 785            self.dialect,
 786            *(gen(k) for k in self.unique_key),
 787            gen(self.valid_from_name),
 788            gen(self.valid_to_name),
 789            str(self.invalidate_hard_deletes),
 790            self.time_data_type.sql(self.dialect),
 791            str(self.batch_size) if self.batch_size is not None else None,
 792        ]
 793
 794    @property
 795    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
 796        return [
 797            *super().metadata_hash_values,
 798            str(self.forward_only),
 799            str(self.disable_restatement),
 800        ]
 801
 802    def to_expression(
 803        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
 804    ) -> d.ModelKind:
 805        return super().to_expression(
 806            expressions=[
 807                *(expressions or []),
 808                *_properties(
 809                    {
 810                        "unique_key": exp.Tuple(expressions=self.unique_key),
 811                        "valid_from_name": self.valid_from_name,
 812                        "valid_to_name": self.valid_to_name,
 813                        "invalidate_hard_deletes": self.invalidate_hard_deletes,
 814                        "time_data_type": self.time_data_type,
 815                        "forward_only": self.forward_only,
 816                        "disable_restatement": self.disable_restatement,
 817                    }
 818                ),
 819            ],
 820        )
 821
 822
 823class SCDType2ByTimeKind(_SCDType2Kind):
 824    name: t.Literal[ModelKindName.SCD_TYPE_2, ModelKindName.SCD_TYPE_2_BY_TIME] = (
 825        ModelKindName.SCD_TYPE_2_BY_TIME
 826    )
 827    updated_at_name: SQLGlotColumn = Field(exp.column("updated_at"), validate_default=True)
 828    updated_at_as_valid_from: SQLGlotBool = False
 829
 830    _always_validate_updated_at = field_validator("updated_at_name", mode="before")(
 831        column_validator
 832    )
 833
 834    @property
 835    def data_hash_values(self) -> t.List[t.Optional[str]]:
 836        return [
 837            *super().data_hash_values,
 838            gen(self.updated_at_name),
 839            str(self.updated_at_as_valid_from),
 840        ]
 841
 842    def to_expression(
 843        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
 844    ) -> d.ModelKind:
 845        return super().to_expression(
 846            expressions=[
 847                *(expressions or []),
 848                *_properties(
 849                    {
 850                        "updated_at_name": self.updated_at_name,
 851                        "updated_at_as_valid_from": self.updated_at_as_valid_from,
 852                    }
 853                ),
 854            ],
 855        )
 856
 857
 858class SCDType2ByColumnKind(_SCDType2Kind):
 859    name: t.Literal[ModelKindName.SCD_TYPE_2_BY_COLUMN] = ModelKindName.SCD_TYPE_2_BY_COLUMN
 860    columns: SQLGlotListOfFieldsOrStar
 861    execution_time_as_valid_from: SQLGlotBool = False
 862    updated_at_name: t.Optional[SQLGlotColumn] = None
 863
 864    @property
 865    def data_hash_values(self) -> t.List[t.Optional[str]]:
 866        columns_sql = (
 867            [gen(c) for c in self.columns]
 868            if isinstance(self.columns, list)
 869            else [gen(self.columns)]
 870        )
 871        return [
 872            *super().data_hash_values,
 873            *columns_sql,
 874            str(self.execution_time_as_valid_from),
 875            gen(self.updated_at_name) if self.updated_at_name is not None else None,
 876        ]
 877
 878    def to_expression(
 879        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
 880    ) -> d.ModelKind:
 881        return super().to_expression(
 882            expressions=[
 883                *(expressions or []),
 884                *_properties(
 885                    {
 886                        "columns": exp.Tuple(expressions=self.columns)
 887                        if isinstance(self.columns, list)
 888                        else self.columns,
 889                        "execution_time_as_valid_from": self.execution_time_as_valid_from,
 890                    }
 891                ),
 892            ],
 893        )
 894
 895
 896class ManagedKind(_ModelKind):
 897    name: t.Literal[ModelKindName.MANAGED] = ModelKindName.MANAGED
 898    disable_restatement: t.Literal[True] = True
 899
 900    @property
 901    def supports_python_models(self) -> bool:
 902        return False
 903
 904
 905class DbtCustomKind(_ModelKind):
 906    name: t.Literal[ModelKindName.DBT_CUSTOM] = ModelKindName.DBT_CUSTOM
 907    materialization: str
 908    adapter: str = "default"
 909    definition: str
 910    dialect: t.Optional[str] = Field(None, validate_default=True)
 911
 912    _dialect_validator = kind_dialect_validator
 913
 914    @field_validator("materialization", "adapter", "definition", mode="before")
 915    @classmethod
 916    def _validate_fields(cls, v: t.Any) -> str:
 917        return validate_string(v)
 918
 919    @property
 920    def data_hash_values(self) -> t.List[t.Optional[str]]:
 921        return [
 922            *super().data_hash_values,
 923            self.materialization,
 924            self.definition,
 925            self.adapter,
 926            self.dialect,
 927        ]
 928
 929    def to_expression(
 930        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
 931    ) -> d.ModelKind:
 932        return super().to_expression(
 933            expressions=[
 934                *(expressions or []),
 935                *_properties(
 936                    {
 937                        "materialization": exp.Literal.string(self.materialization),
 938                        "adapter": exp.Literal.string(self.adapter),
 939                    }
 940                ),
 941            ],
 942        )
 943
 944
 945class EmbeddedKind(_ModelKind):
 946    name: t.Literal[ModelKindName.EMBEDDED] = ModelKindName.EMBEDDED
 947
 948    @property
 949    def supports_python_models(self) -> bool:
 950        return False
 951
 952
 953class ExternalKind(_ModelKind):
 954    name: t.Literal[ModelKindName.EXTERNAL] = ModelKindName.EXTERNAL
 955
 956
 957class CustomKind(_ModelKind):
 958    name: t.Literal[ModelKindName.CUSTOM] = ModelKindName.CUSTOM
 959    materialization: str
 960    materialization_properties_: t.Optional[exp.Tuple] = Field(
 961        default=None, alias="materialization_properties"
 962    )
 963    forward_only: SQLGlotBool = False
 964    disable_restatement: SQLGlotBool = False
 965    batch_size: t.Optional[SQLGlotPositiveInt] = None
 966    batch_concurrency: t.Optional[SQLGlotPositiveInt] = None
 967    lookback: t.Optional[SQLGlotPositiveInt] = None
 968    auto_restatement_cron: t.Optional[SQLGlotCron] = None
 969    auto_restatement_intervals: t.Optional[SQLGlotPositiveInt] = None
 970
 971    # so that CustomKind subclasses know the dialect when validating / normalizing / interpreting values in `materialization_properties`
 972    dialect: str = Field(exclude=True)
 973
 974    _properties_validator = properties_validator
 975
 976    @field_validator("materialization", mode="before")
 977    @classmethod
 978    def _validate_materialization(cls, v: t.Any) -> str:
 979        # note: create_model_kind() validates the custom materialization class
 980        return validate_string(v)
 981
 982    @property
 983    def materialization_properties(self) -> CustomMaterializationProperties:
 984        """A dictionary of materialization properties."""
 985        if not self.materialization_properties_:
 986            return {}
 987        return d.interpret_key_value_pairs(self.materialization_properties_)
 988
 989    @property
 990    def data_hash_values(self) -> t.List[t.Optional[str]]:
 991        return [
 992            *super().data_hash_values,
 993            self.materialization,
 994            gen(self.materialization_properties_) if self.materialization_properties_ else None,
 995            str(self.lookback) if self.lookback is not None else None,
 996        ]
 997
 998    @property
 999    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
1000        return [
1001            *super().metadata_hash_values,
1002            str(self.batch_size) if self.batch_size is not None else None,
1003            str(self.batch_concurrency) if self.batch_concurrency is not None else None,
1004            str(self.forward_only),
1005            str(self.disable_restatement),
1006            self.auto_restatement_cron,
1007            str(self.auto_restatement_intervals)
1008            if self.auto_restatement_intervals is not None
1009            else None,
1010        ]
1011
1012    def to_expression(
1013        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
1014    ) -> d.ModelKind:
1015        return super().to_expression(
1016            expressions=[
1017                *(expressions or []),
1018                *_properties(
1019                    {
1020                        "materialization": exp.Literal.string(self.materialization),
1021                        "materialization_properties": self.materialization_properties_,
1022                        "forward_only": self.forward_only,
1023                        "disable_restatement": self.disable_restatement,
1024                        "batch_size": self.batch_size,
1025                        "batch_concurrency": self.batch_concurrency,
1026                        "lookback": self.lookback,
1027                        "auto_restatement_cron": self.auto_restatement_cron,
1028                        "auto_restatement_intervals": self.auto_restatement_intervals,
1029                    }
1030                ),
1031            ],
1032        )
1033
1034
1035ModelKind = t.Annotated[
1036    t.Union[
1037        EmbeddedKind,
1038        ExternalKind,
1039        FullKind,
1040        IncrementalByTimeRangeKind,
1041        IncrementalByUniqueKeyKind,
1042        IncrementalByPartitionKind,
1043        IncrementalUnmanagedKind,
1044        SeedKind,
1045        ViewKind,
1046        SCDType2ByTimeKind,
1047        SCDType2ByColumnKind,
1048        CustomKind,
1049        ManagedKind,
1050        DbtCustomKind,
1051    ],
1052    Field(discriminator="name"),
1053]
1054
1055MODEL_KIND_NAME_TO_TYPE: t.Dict[str, t.Type[ModelKind]] = {
1056    ModelKindName.EMBEDDED: EmbeddedKind,
1057    ModelKindName.EXTERNAL: ExternalKind,
1058    ModelKindName.FULL: FullKind,
1059    ModelKindName.INCREMENTAL_BY_TIME_RANGE: IncrementalByTimeRangeKind,
1060    ModelKindName.INCREMENTAL_BY_UNIQUE_KEY: IncrementalByUniqueKeyKind,
1061    ModelKindName.INCREMENTAL_BY_PARTITION: IncrementalByPartitionKind,
1062    ModelKindName.INCREMENTAL_UNMANAGED: IncrementalUnmanagedKind,
1063    ModelKindName.SEED: SeedKind,
1064    ModelKindName.VIEW: ViewKind,
1065    ModelKindName.SCD_TYPE_2: SCDType2ByTimeKind,
1066    ModelKindName.SCD_TYPE_2_BY_TIME: SCDType2ByTimeKind,
1067    ModelKindName.SCD_TYPE_2_BY_COLUMN: SCDType2ByColumnKind,
1068    ModelKindName.CUSTOM: CustomKind,
1069    ModelKindName.MANAGED: ManagedKind,
1070    ModelKindName.DBT_CUSTOM: DbtCustomKind,
1071}
1072
1073
1074def model_kind_type_from_name(name: t.Optional[str]) -> t.Type[ModelKind]:
1075    klass = MODEL_KIND_NAME_TO_TYPE.get(name) if name else None
1076    if not klass:
1077        raise ConfigError(f"Invalid model kind '{name}'")
1078    return t.cast(t.Type[ModelKind], klass)
1079
1080
1081def create_model_kind(v: t.Any, dialect: str, defaults: t.Dict[str, t.Any]) -> ModelKind:
1082    if isinstance(v, _ModelKind):
1083        return t.cast(ModelKind, v)
1084
1085    if isinstance(v, (d.ModelKind, dict)):
1086        props = (
1087            {prop.name: prop.args.get("value") for prop in v.expressions}
1088            if isinstance(v, d.ModelKind)
1089            else v
1090        )
1091        name = v.this if isinstance(v, d.ModelKind) else props.get("name")
1092
1093        # We want to ensure whatever name is provided to construct the class is the same name that will be
1094        # found inside the class itself in order to avoid a change during plan/apply for legacy aliases.
1095        # Ex: Pass in `SCD_TYPE_2` then we want to ensure we get `SCD_TYPE_2` as the kind name
1096        # instead of `SCD_TYPE_2_BY_TIME`.
1097        props["name"] = name
1098        kind_type = model_kind_type_from_name(name)
1099
1100        if "dialect" in kind_type.all_fields() and props.get("dialect") is None:
1101            props["dialect"] = dialect
1102
1103        # only pass the on_destructive_change or on_additive_change user default to models inheriting from _Incremental
1104        # that don't explicitly set it in the model definition
1105        if issubclass(kind_type, _Incremental):
1106            for on_change_property in ("on_additive_change", "on_destructive_change"):
1107                if (
1108                    props.get(on_change_property) is None
1109                    and defaults.get(on_change_property) is not None
1110                ):
1111                    props[on_change_property] = defaults.get(on_change_property)
1112
1113        # only pass the batch_concurrency user default to models inheriting from _IncrementalBy
1114        # that don't explicitly set it in the model definition, but ignore subclasses of _IncrementalBy
1115        # that hardcode a specific batch_concurrency
1116        if issubclass(kind_type, _IncrementalBy):
1117            BATCH_CONCURRENCY: t.Final = "batch_concurrency"
1118            if (
1119                props.get(BATCH_CONCURRENCY) is None
1120                and defaults.get(BATCH_CONCURRENCY) is not None
1121                and kind_type.all_field_infos()[BATCH_CONCURRENCY].default is None
1122            ):
1123                props[BATCH_CONCURRENCY] = defaults.get(BATCH_CONCURRENCY)
1124
1125        if kind_type == CustomKind:
1126            # load the custom materialization class and check if it uses a custom kind type
1127            from sqlmesh.core.snapshot.evaluator import get_custom_materialization_type
1128
1129            if "materialization" not in props:
1130                raise ConfigError(
1131                    "The 'materialization' property is required for models of the CUSTOM kind"
1132                )
1133
1134            # The below call will print a warning if a materialization with the given name doesn't exist
1135            # we dont want to throw an error here because we still want Models with a CustomKind to be able
1136            # to be serialized / deserialized in contexts where the custom materialization class may not be available,
1137            # such as in HTTP request handlers
1138            custom_materialization = get_custom_materialization_type(
1139                validate_string(props.get("materialization")), raise_errors=False
1140            )
1141            if custom_materialization is not None:
1142                actual_kind_type, _ = custom_materialization
1143                return actual_kind_type(**props)
1144
1145        validate_extra_and_required_fields(
1146            kind_type, set(props), f"MODEL block 'kind {name}' field"
1147        )
1148        return kind_type(**props)
1149
1150    name = (v.name if isinstance(v, exp.Expr) else str(v)).upper()
1151    return model_kind_type_from_name(name)(name=name)  # type: ignore
1152
1153
1154def _model_kind_validator(cls: t.Type, v: t.Any, info: t.Optional[ValidationInfo]) -> ModelKind:
1155    dialect = get_dialect(info.data) if info else ""
1156    return create_model_kind(v, dialect, {})
1157
1158
1159model_kind_validator: t.Callable = field_validator("kind", mode="before")(_model_kind_validator)
1160
1161
1162def _property(name: str, value: t.Any) -> exp.Property:
1163    return exp.Property(this=exp.var(name), value=exp.convert(value))
1164
1165
1166def _properties(name_value_pairs: t.Dict[str, t.Any]) -> t.List[exp.Property]:
1167    return [_property(k, v) for k, v in name_value_pairs.items() if v is not None]
class ModelKindMixin:
 47class ModelKindMixin:
 48    @property
 49    def model_kind_name(self) -> t.Optional[ModelKindName]:
 50        """Returns the model kind name."""
 51        raise NotImplementedError
 52
 53    @property
 54    def is_incremental_by_time_range(self) -> bool:
 55        return self.model_kind_name == ModelKindName.INCREMENTAL_BY_TIME_RANGE
 56
 57    @property
 58    def is_incremental_by_unique_key(self) -> bool:
 59        return self.model_kind_name == ModelKindName.INCREMENTAL_BY_UNIQUE_KEY
 60
 61    @property
 62    def is_incremental_by_partition(self) -> bool:
 63        return self.model_kind_name == ModelKindName.INCREMENTAL_BY_PARTITION
 64
 65    @property
 66    def is_incremental_unmanaged(self) -> bool:
 67        return self.model_kind_name == ModelKindName.INCREMENTAL_UNMANAGED
 68
 69    @property
 70    def is_incremental(self) -> bool:
 71        return (
 72            self.is_incremental_by_time_range
 73            or self.is_incremental_by_unique_key
 74            or self.is_incremental_by_partition
 75            or self.is_incremental_unmanaged
 76            or self.is_scd_type_2
 77        )
 78
 79    @property
 80    def is_full(self) -> bool:
 81        return self.model_kind_name == ModelKindName.FULL
 82
 83    @property
 84    def is_view(self) -> bool:
 85        return self.model_kind_name == ModelKindName.VIEW
 86
 87    @property
 88    def is_embedded(self) -> bool:
 89        return self.model_kind_name == ModelKindName.EMBEDDED
 90
 91    @property
 92    def is_seed(self) -> bool:
 93        return self.model_kind_name == ModelKindName.SEED
 94
 95    @property
 96    def is_external(self) -> bool:
 97        return self.model_kind_name == ModelKindName.EXTERNAL
 98
 99    @property
100    def is_scd_type_2(self) -> bool:
101        return self.model_kind_name in {
102            ModelKindName.SCD_TYPE_2,
103            ModelKindName.SCD_TYPE_2_BY_TIME,
104            ModelKindName.SCD_TYPE_2_BY_COLUMN,
105        }
106
107    @property
108    def is_scd_type_2_by_time(self) -> bool:
109        return self.model_kind_name in {ModelKindName.SCD_TYPE_2, ModelKindName.SCD_TYPE_2_BY_TIME}
110
111    @property
112    def is_scd_type_2_by_column(self) -> bool:
113        return self.model_kind_name == ModelKindName.SCD_TYPE_2_BY_COLUMN
114
115    @property
116    def is_custom(self) -> bool:
117        return self.model_kind_name == ModelKindName.CUSTOM
118
119    @property
120    def is_managed(self) -> bool:
121        return self.model_kind_name == ModelKindName.MANAGED
122
123    @property
124    def is_dbt_custom(self) -> bool:
125        return self.model_kind_name == ModelKindName.DBT_CUSTOM
126
127    @property
128    def is_symbolic(self) -> bool:
129        """A symbolic model is one that doesn't execute at all."""
130        return self.model_kind_name in (ModelKindName.EMBEDDED, ModelKindName.EXTERNAL)
131
132    @property
133    def is_materialized(self) -> bool:
134        return self.model_kind_name is not None and not (self.is_symbolic or self.is_view)
135
136    @property
137    def only_execution_time(self) -> bool:
138        """Whether or not this model only cares about execution time to render."""
139        return self.is_view or self.is_full
140
141    @property
142    def full_history_restatement_only(self) -> bool:
143        """Whether or not this model only supports restatement of full history."""
144        return (
145            self.is_incremental_unmanaged
146            or self.is_incremental_by_unique_key
147            or self.is_incremental_by_partition
148            or self.is_scd_type_2
149            or self.is_managed
150            or self.is_full
151            or self.is_view
152        )
153
154    @property
155    def supports_python_models(self) -> bool:
156        return True
157
158    @property
159    def supports_grants(self) -> bool:
160        """Whether this model kind supports grants configuration."""
161        return self.is_materialized or self.is_view
model_kind_name: Optional[ModelKindName]
48    @property
49    def model_kind_name(self) -> t.Optional[ModelKindName]:
50        """Returns the model kind name."""
51        raise NotImplementedError

Returns the model kind name.

is_incremental_by_time_range: bool
53    @property
54    def is_incremental_by_time_range(self) -> bool:
55        return self.model_kind_name == ModelKindName.INCREMENTAL_BY_TIME_RANGE
is_incremental_by_unique_key: bool
57    @property
58    def is_incremental_by_unique_key(self) -> bool:
59        return self.model_kind_name == ModelKindName.INCREMENTAL_BY_UNIQUE_KEY
is_incremental_by_partition: bool
61    @property
62    def is_incremental_by_partition(self) -> bool:
63        return self.model_kind_name == ModelKindName.INCREMENTAL_BY_PARTITION
is_incremental_unmanaged: bool
65    @property
66    def is_incremental_unmanaged(self) -> bool:
67        return self.model_kind_name == ModelKindName.INCREMENTAL_UNMANAGED
is_incremental: bool
69    @property
70    def is_incremental(self) -> bool:
71        return (
72            self.is_incremental_by_time_range
73            or self.is_incremental_by_unique_key
74            or self.is_incremental_by_partition
75            or self.is_incremental_unmanaged
76            or self.is_scd_type_2
77        )
is_full: bool
79    @property
80    def is_full(self) -> bool:
81        return self.model_kind_name == ModelKindName.FULL
is_view: bool
83    @property
84    def is_view(self) -> bool:
85        return self.model_kind_name == ModelKindName.VIEW
is_embedded: bool
87    @property
88    def is_embedded(self) -> bool:
89        return self.model_kind_name == ModelKindName.EMBEDDED
is_seed: bool
91    @property
92    def is_seed(self) -> bool:
93        return self.model_kind_name == ModelKindName.SEED
is_external: bool
95    @property
96    def is_external(self) -> bool:
97        return self.model_kind_name == ModelKindName.EXTERNAL
is_scd_type_2: bool
 99    @property
100    def is_scd_type_2(self) -> bool:
101        return self.model_kind_name in {
102            ModelKindName.SCD_TYPE_2,
103            ModelKindName.SCD_TYPE_2_BY_TIME,
104            ModelKindName.SCD_TYPE_2_BY_COLUMN,
105        }
is_scd_type_2_by_time: bool
107    @property
108    def is_scd_type_2_by_time(self) -> bool:
109        return self.model_kind_name in {ModelKindName.SCD_TYPE_2, ModelKindName.SCD_TYPE_2_BY_TIME}
is_scd_type_2_by_column: bool
111    @property
112    def is_scd_type_2_by_column(self) -> bool:
113        return self.model_kind_name == ModelKindName.SCD_TYPE_2_BY_COLUMN
is_custom: bool
115    @property
116    def is_custom(self) -> bool:
117        return self.model_kind_name == ModelKindName.CUSTOM
is_managed: bool
119    @property
120    def is_managed(self) -> bool:
121        return self.model_kind_name == ModelKindName.MANAGED
is_dbt_custom: bool
123    @property
124    def is_dbt_custom(self) -> bool:
125        return self.model_kind_name == ModelKindName.DBT_CUSTOM
is_symbolic: bool
127    @property
128    def is_symbolic(self) -> bool:
129        """A symbolic model is one that doesn't execute at all."""
130        return self.model_kind_name in (ModelKindName.EMBEDDED, ModelKindName.EXTERNAL)

A symbolic model is one that doesn't execute at all.

is_materialized: bool
132    @property
133    def is_materialized(self) -> bool:
134        return self.model_kind_name is not None and not (self.is_symbolic or self.is_view)
only_execution_time: bool
136    @property
137    def only_execution_time(self) -> bool:
138        """Whether or not this model only cares about execution time to render."""
139        return self.is_view or self.is_full

Whether or not this model only cares about execution time to render.

full_history_restatement_only: bool
141    @property
142    def full_history_restatement_only(self) -> bool:
143        """Whether or not this model only supports restatement of full history."""
144        return (
145            self.is_incremental_unmanaged
146            or self.is_incremental_by_unique_key
147            or self.is_incremental_by_partition
148            or self.is_scd_type_2
149            or self.is_managed
150            or self.is_full
151            or self.is_view
152        )

Whether or not this model only supports restatement of full history.

supports_python_models: bool
154    @property
155    def supports_python_models(self) -> bool:
156        return True
supports_grants: bool
158    @property
159    def supports_grants(self) -> bool:
160        """Whether this model kind supports grants configuration."""
161        return self.is_materialized or self.is_view

Whether this model kind supports grants configuration.

class ModelKindName(builtins.str, ModelKindMixin, enum.Enum):
164class ModelKindName(str, ModelKindMixin, Enum):
165    """The kind of model, determining how this data is computed and stored in the warehouse."""
166
167    INCREMENTAL_BY_TIME_RANGE = "INCREMENTAL_BY_TIME_RANGE"
168    INCREMENTAL_BY_UNIQUE_KEY = "INCREMENTAL_BY_UNIQUE_KEY"
169    INCREMENTAL_BY_PARTITION = "INCREMENTAL_BY_PARTITION"
170    INCREMENTAL_UNMANAGED = "INCREMENTAL_UNMANAGED"
171    FULL = "FULL"
172    # Legacy alias to SCD Type 2 By Time
173    # Only used for Parsing and mapping name to SCD Type 2 By Time
174    SCD_TYPE_2 = "SCD_TYPE_2"
175    SCD_TYPE_2_BY_TIME = "SCD_TYPE_2_BY_TIME"
176    SCD_TYPE_2_BY_COLUMN = "SCD_TYPE_2_BY_COLUMN"
177    VIEW = "VIEW"
178    EMBEDDED = "EMBEDDED"
179    SEED = "SEED"
180    EXTERNAL = "EXTERNAL"
181    CUSTOM = "CUSTOM"
182    MANAGED = "MANAGED"
183    DBT_CUSTOM = "DBT_CUSTOM"
184
185    @property
186    def model_kind_name(self) -> t.Optional[ModelKindName]:
187        return self
188
189    def __str__(self) -> str:
190        return self.name
191
192    def __repr__(self) -> str:
193        return str(self)

The kind of model, determining how this data is computed and stored in the warehouse.

INCREMENTAL_BY_TIME_RANGE = INCREMENTAL_BY_TIME_RANGE
INCREMENTAL_BY_UNIQUE_KEY = INCREMENTAL_BY_UNIQUE_KEY
INCREMENTAL_BY_PARTITION = INCREMENTAL_BY_PARTITION
INCREMENTAL_UNMANAGED = INCREMENTAL_UNMANAGED
FULL = FULL
SCD_TYPE_2 = SCD_TYPE_2
SCD_TYPE_2_BY_TIME = SCD_TYPE_2_BY_TIME
SCD_TYPE_2_BY_COLUMN = SCD_TYPE_2_BY_COLUMN
VIEW = VIEW
EMBEDDED = EMBEDDED
SEED = SEED
EXTERNAL = EXTERNAL
CUSTOM = CUSTOM
MANAGED = MANAGED
DBT_CUSTOM = DBT_CUSTOM
model_kind_name: Optional[ModelKindName]
185    @property
186    def model_kind_name(self) -> t.Optional[ModelKindName]:
187        return self

Returns the model kind name.

Inherited Members
ModelKindMixin
is_incremental_by_time_range
is_incremental_by_unique_key
is_incremental_by_partition
is_incremental_unmanaged
is_incremental
is_full
is_view
is_embedded
is_seed
is_external
is_scd_type_2
is_scd_type_2_by_time
is_scd_type_2_by_column
is_custom
is_managed
is_dbt_custom
is_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_python_models
supports_grants
enum.Enum
name
value
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
class OnDestructiveChange(builtins.str, enum.Enum):
196class OnDestructiveChange(str, Enum):
197    """What should happen when a forward-only model change requires a destructive schema change."""
198
199    ERROR = "ERROR"
200    WARN = "WARN"
201    ALLOW = "ALLOW"
202    IGNORE = "IGNORE"
203
204    @property
205    def is_error(self) -> bool:
206        return self == OnDestructiveChange.ERROR
207
208    @property
209    def is_warn(self) -> bool:
210        return self == OnDestructiveChange.WARN
211
212    @property
213    def is_allow(self) -> bool:
214        return self == OnDestructiveChange.ALLOW
215
216    @property
217    def is_ignore(self) -> bool:
218        return self == OnDestructiveChange.IGNORE

What should happen when a forward-only model change requires a destructive schema change.

ERROR = <OnDestructiveChange.ERROR: 'ERROR'>
WARN = <OnDestructiveChange.WARN: 'WARN'>
ALLOW = <OnDestructiveChange.ALLOW: 'ALLOW'>
IGNORE = <OnDestructiveChange.IGNORE: 'IGNORE'>
is_error: bool
204    @property
205    def is_error(self) -> bool:
206        return self == OnDestructiveChange.ERROR
is_warn: bool
208    @property
209    def is_warn(self) -> bool:
210        return self == OnDestructiveChange.WARN
is_allow: bool
212    @property
213    def is_allow(self) -> bool:
214        return self == OnDestructiveChange.ALLOW
is_ignore: bool
216    @property
217    def is_ignore(self) -> bool:
218        return self == OnDestructiveChange.IGNORE
Inherited Members
enum.Enum
name
value
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
class OnAdditiveChange(builtins.str, enum.Enum):
221class OnAdditiveChange(str, Enum):
222    """What should happen when a forward-only model change requires an additive schema change."""
223
224    ERROR = "ERROR"
225    WARN = "WARN"
226    ALLOW = "ALLOW"
227    IGNORE = "IGNORE"
228
229    @property
230    def is_error(self) -> bool:
231        return self == OnAdditiveChange.ERROR
232
233    @property
234    def is_warn(self) -> bool:
235        return self == OnAdditiveChange.WARN
236
237    @property
238    def is_allow(self) -> bool:
239        return self == OnAdditiveChange.ALLOW
240
241    @property
242    def is_ignore(self) -> bool:
243        return self == OnAdditiveChange.IGNORE

What should happen when a forward-only model change requires an additive schema change.

ERROR = <OnAdditiveChange.ERROR: 'ERROR'>
WARN = <OnAdditiveChange.WARN: 'WARN'>
ALLOW = <OnAdditiveChange.ALLOW: 'ALLOW'>
IGNORE = <OnAdditiveChange.IGNORE: 'IGNORE'>
is_error: bool
229    @property
230    def is_error(self) -> bool:
231        return self == OnAdditiveChange.ERROR
is_warn: bool
233    @property
234    def is_warn(self) -> bool:
235        return self == OnAdditiveChange.WARN
is_allow: bool
237    @property
238    def is_allow(self) -> bool:
239        return self == OnAdditiveChange.ALLOW
is_ignore: bool
241    @property
242    def is_ignore(self) -> bool:
243        return self == OnAdditiveChange.IGNORE
Inherited Members
enum.Enum
name
value
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 on_additive_change_validator( cls: Type, v: Union[OnAdditiveChange, str, sqlglot.expressions.core.Identifier]) -> Any:
256def _on_additive_change_validator(
257    cls: t.Type, v: t.Union[OnAdditiveChange, str, exp.Identifier]
258) -> t.Any:
259    if v and not isinstance(v, OnAdditiveChange):
260        return OnAdditiveChange(
261            v.this.upper() if isinstance(v, (exp.Identifier, exp.Literal)) else v.upper()
262        )
263    return v

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.
def on_destructive_change_validator( cls: Type, v: Union[OnDestructiveChange, str, sqlglot.expressions.core.Identifier]) -> Any:
246def _on_destructive_change_validator(
247    cls: t.Type, v: t.Union[OnDestructiveChange, str, exp.Identifier]
248) -> t.Any:
249    if v and not isinstance(v, OnDestructiveChange):
250        return OnDestructiveChange(
251            v.this.upper() if isinstance(v, (exp.Identifier, exp.Literal)) else v.upper()
252        )
253    return v

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 TimeColumn(sqlmesh.utils.pydantic.PydanticModel):
297class TimeColumn(PydanticModel):
298    column: exp.Expr
299    format: t.Optional[str] = None
300
301    @classmethod
302    def validator(cls) -> classmethod:
303        def _time_column_validator(v: t.Any, info: ValidationInfo) -> TimeColumn:
304            return TimeColumn.create(v, get_dialect(info.data))
305
306        return field_validator("time_column", mode="before")(_time_column_validator)
307
308    @field_validator("column", mode="before")
309    @classmethod
310    def _column_validator(cls, v: t.Union[str, exp.Expr]) -> exp.Expr:
311        if not v:
312            raise ConfigError("Time Column cannot be empty.")
313        if isinstance(v, str):
314            return exp.to_column(v)
315        return v
316
317    @property
318    def expression(self) -> exp.Expr:
319        """Convert this pydantic model into a time_column SQLGlot expression."""
320        if not self.format:
321            return self.column
322
323        return exp.Tuple(expressions=[self.column, exp.Literal.string(self.format)])
324
325    def to_expression(self, dialect: str) -> exp.Expr:
326        """Convert this pydantic model into a time_column SQLGlot expression."""
327        if not self.format:
328            return self.column
329
330        return exp.Tuple(
331            expressions=[
332                self.column,
333                exp.Literal.string(
334                    format_time(self.format, d.Dialect.get_or_raise(dialect).INVERSE_TIME_MAPPING)
335                ),
336            ]
337        )
338
339    def to_property(self, dialect: str = "") -> exp.Property:
340        return exp.Property(this="time_column", value=self.to_expression(dialect))
341
342    @classmethod
343    def create(cls, v: t.Any, dialect: str) -> Self:
344        if isinstance(v, exp.Tuple):
345            if not v.expressions:
346                raise ConfigError("Time Column cannot be empty.")
347            column_expr = v.expressions[0]
348            column = (
349                exp.column(column_expr) if isinstance(column_expr, exp.Identifier) else column_expr
350            )
351            format = v.expressions[1].name if len(v.expressions) > 1 else None
352        elif isinstance(v, exp.Expr):
353            column = exp.column(v) if isinstance(v, exp.Identifier) else v
354            format = None
355        elif isinstance(v, str):
356            column = d.parse_one(v, dialect=dialect)
357            column.meta.pop("sql")
358            format = None
359        elif isinstance(v, dict):
360            column_raw = v["column"]
361            column = (
362                d.parse_one(column_raw, dialect=dialect)
363                if isinstance(column_raw, str)
364                else column_raw
365            )
366            format = v.get("format")
367        elif isinstance(v, TimeColumn):
368            column = v.column
369            format = v.format
370        else:
371            raise ConfigError(f"Invalid time_column: '{v}'.")
372
373        column = quote_identifiers(normalize_identifiers(column, dialect=dialect), dialect=dialect)
374        column.meta["dialect"] = dialect
375
376        return cls(column=column, format=format)

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
column: sqlglot.expressions.core.Expr
format: Optional[str]
@classmethod
def validator(cls) -> classmethod:
301    @classmethod
302    def validator(cls) -> classmethod:
303        def _time_column_validator(v: t.Any, info: ValidationInfo) -> TimeColumn:
304            return TimeColumn.create(v, get_dialect(info.data))
305
306        return field_validator("time_column", mode="before")(_time_column_validator)
expression: sqlglot.expressions.core.Expr
317    @property
318    def expression(self) -> exp.Expr:
319        """Convert this pydantic model into a time_column SQLGlot expression."""
320        if not self.format:
321            return self.column
322
323        return exp.Tuple(expressions=[self.column, exp.Literal.string(self.format)])

Convert this pydantic model into a time_column SQLGlot expression.

def to_expression(self, dialect: str) -> sqlglot.expressions.core.Expr:
325    def to_expression(self, dialect: str) -> exp.Expr:
326        """Convert this pydantic model into a time_column SQLGlot expression."""
327        if not self.format:
328            return self.column
329
330        return exp.Tuple(
331            expressions=[
332                self.column,
333                exp.Literal.string(
334                    format_time(self.format, d.Dialect.get_or_raise(dialect).INVERSE_TIME_MAPPING)
335                ),
336            ]
337        )

Convert this pydantic model into a time_column SQLGlot expression.

def to_property(self, dialect: str = '') -> sqlglot.expressions.properties.Property:
339    def to_property(self, dialect: str = "") -> exp.Property:
340        return exp.Property(this="time_column", value=self.to_expression(dialect))
@classmethod
def create(cls, v: Any, dialect: str) -> typing_extensions.Self:
342    @classmethod
343    def create(cls, v: t.Any, dialect: str) -> Self:
344        if isinstance(v, exp.Tuple):
345            if not v.expressions:
346                raise ConfigError("Time Column cannot be empty.")
347            column_expr = v.expressions[0]
348            column = (
349                exp.column(column_expr) if isinstance(column_expr, exp.Identifier) else column_expr
350            )
351            format = v.expressions[1].name if len(v.expressions) > 1 else None
352        elif isinstance(v, exp.Expr):
353            column = exp.column(v) if isinstance(v, exp.Identifier) else v
354            format = None
355        elif isinstance(v, str):
356            column = d.parse_one(v, dialect=dialect)
357            column.meta.pop("sql")
358            format = None
359        elif isinstance(v, dict):
360            column_raw = v["column"]
361            column = (
362                d.parse_one(column_raw, dialect=dialect)
363                if isinstance(column_raw, str)
364                else column_raw
365            )
366            format = v.get("format")
367        elif isinstance(v, TimeColumn):
368            column = v.column
369            format = v.format
370        else:
371            raise ConfigError(f"Invalid time_column: '{v}'.")
372
373        column = quote_identifiers(normalize_identifiers(column, dialect=dialect), dialect=dialect)
374        column.meta["dialect"] = dialect
375
376        return cls(column=column, format=format)
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
dict
json
copy
fields_set
parse_obj
parse_raw
missing_required_fields
extra_fields
all_fields
all_field_infos
required_fields
def kind_dialect_validator(cls: Type, v: Optional[str]) -> str:
379def _kind_dialect_validator(cls: t.Type, v: t.Optional[str]) -> str:
380    if v is None:
381        return get_dialect({})
382    return v

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 IncrementalByTimeRangeKind(_IncrementalBy):
468class IncrementalByTimeRangeKind(_IncrementalBy):
469    name: t.Literal[ModelKindName.INCREMENTAL_BY_TIME_RANGE] = (
470        ModelKindName.INCREMENTAL_BY_TIME_RANGE
471    )
472    time_column: TimeColumn
473    auto_restatement_intervals: t.Optional[SQLGlotPositiveInt] = None
474    partition_by_time_column: SQLGlotBool = True
475
476    _time_column_validator = TimeColumn.validator()
477
478    def to_expression(
479        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
480    ) -> d.ModelKind:
481        return super().to_expression(
482            expressions=[
483                *(expressions or []),
484                self.time_column.to_property(kwargs.get("dialect") or ""),
485                *_properties(
486                    {
487                        "partition_by_time_column": self.partition_by_time_column,
488                    }
489                ),
490                *(
491                    [_property("auto_restatement_intervals", self.auto_restatement_intervals)]
492                    if self.auto_restatement_intervals is not None
493                    else []
494                ),
495            ]
496        )
497
498    @property
499    def data_hash_values(self) -> t.List[t.Optional[str]]:
500        return [*super().data_hash_values, gen(self.time_column.column), self.time_column.format]
501
502    @property
503    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
504        return [
505            *super().metadata_hash_values,
506            str(self.partition_by_time_column),
507            str(self.auto_restatement_intervals)
508            if self.auto_restatement_intervals is not None
509            else None,
510        ]

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
name: Literal[INCREMENTAL_BY_TIME_RANGE]
time_column: TimeColumn
auto_restatement_intervals: Optional[Annotated[int, BeforeValidator(func=<function positive_int_validator at 0x7a2adca28550>, json_schema_input_type=PydanticUndefined)]]
partition_by_time_column: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x7a2adca284c0>, json_schema_input_type=PydanticUndefined)]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.core.Expr]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
478    def to_expression(
479        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
480    ) -> d.ModelKind:
481        return super().to_expression(
482            expressions=[
483                *(expressions or []),
484                self.time_column.to_property(kwargs.get("dialect") or ""),
485                *_properties(
486                    {
487                        "partition_by_time_column": self.partition_by_time_column,
488                    }
489                ),
490                *(
491                    [_property("auto_restatement_intervals", self.auto_restatement_intervals)]
492                    if self.auto_restatement_intervals is not None
493                    else []
494                ),
495            ]
496        )
data_hash_values: List[Optional[str]]
498    @property
499    def data_hash_values(self) -> t.List[t.Optional[str]]:
500        return [*super().data_hash_values, gen(self.time_column.column), self.time_column.format]
metadata_hash_values: List[Optional[str]]
502    @property
503    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
504        return [
505            *super().metadata_hash_values,
506            str(self.partition_by_time_column),
507            str(self.auto_restatement_intervals)
508            if self.auto_restatement_intervals is not None
509            else None,
510        ]
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].

class IncrementalByUniqueKeyKind(_IncrementalBy):
513class IncrementalByUniqueKeyKind(_IncrementalBy):
514    name: t.Literal[ModelKindName.INCREMENTAL_BY_UNIQUE_KEY] = (
515        ModelKindName.INCREMENTAL_BY_UNIQUE_KEY
516    )
517    unique_key: SQLGlotListOfFields
518    when_matched: t.Optional[exp.Whens] = None
519    merge_filter: t.Optional[exp.Expr] = None
520    batch_concurrency: t.Literal[1] = 1
521
522    @field_validator("when_matched", mode="before")
523    def _when_matched_validator(
524        cls,
525        v: t.Optional[t.Union[str, list, exp.Whens]],
526        info: ValidationInfo,
527    ) -> t.Optional[exp.Whens]:
528        if v is None:
529            return v
530        if isinstance(v, list):
531            v = " ".join(v)
532
533        dialect = get_dialect(info.data)
534
535        if isinstance(v, str):
536            # Whens wrap the WHEN clauses, but the parentheses aren't parsed by sqlglot
537            v = v.strip()
538            if v.startswith("("):
539                v = v[1:-1]
540
541            v = t.cast(exp.Whens, d.parse_one(v, into=exp.Whens, dialect=dialect))
542
543        v = validate_expression(v, dialect=dialect)
544        return t.cast(exp.Whens, v.transform(d.replace_merge_table_aliases, dialect=dialect))
545
546    @field_validator("merge_filter", mode="before")
547    def _merge_filter_validator(
548        cls,
549        v: t.Optional[exp.Expr],
550        info: ValidationInfo,
551    ) -> t.Optional[exp.Expr]:
552        if v is None:
553            return v
554
555        dialect = get_dialect(info.data)
556
557        if isinstance(v, str):
558            v = v.strip()
559            v = d.parse_one(v, dialect=dialect)
560
561        v = validate_expression(v, dialect=dialect)
562        return v.transform(d.replace_merge_table_aliases, dialect=dialect)
563
564    @property
565    def data_hash_values(self) -> t.List[t.Optional[str]]:
566        return [
567            *super().data_hash_values,
568            *(gen(k) for k in self.unique_key),
569            gen(self.when_matched) if self.when_matched is not None else None,
570            gen(self.merge_filter) if self.merge_filter is not None else None,
571        ]
572
573    def to_expression(
574        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
575    ) -> d.ModelKind:
576        return super().to_expression(
577            expressions=[
578                *(expressions or []),
579                *_properties(
580                    {
581                        "unique_key": exp.Tuple(expressions=self.unique_key),
582                        "when_matched": self.when_matched,
583                        "merge_filter": self.merge_filter,
584                    }
585                ),
586            ],
587        )

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
name: Literal[INCREMENTAL_BY_UNIQUE_KEY]
unique_key: Annotated[List[sqlglot.expressions.core.Expr], BeforeValidator(func=<function list_of_fields_validator at 0x7a2adca28820>, json_schema_input_type=PydanticUndefined)]
when_matched: Optional[sqlglot.expressions.dml.Whens]
merge_filter: Optional[sqlglot.expressions.core.Expr]
batch_concurrency: Literal[1]
data_hash_values: List[Optional[str]]
564    @property
565    def data_hash_values(self) -> t.List[t.Optional[str]]:
566        return [
567            *super().data_hash_values,
568            *(gen(k) for k in self.unique_key),
569            gen(self.when_matched) if self.when_matched is not None else None,
570            gen(self.merge_filter) if self.merge_filter is not None else None,
571        ]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.core.Expr]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
573    def to_expression(
574        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
575    ) -> d.ModelKind:
576        return super().to_expression(
577            expressions=[
578                *(expressions or []),
579                *_properties(
580                    {
581                        "unique_key": exp.Tuple(expressions=self.unique_key),
582                        "when_matched": self.when_matched,
583                        "merge_filter": self.merge_filter,
584                    }
585                ),
586            ],
587        )
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].

class IncrementalByPartitionKind(_Incremental):
590class IncrementalByPartitionKind(_Incremental):
591    name: t.Literal[ModelKindName.INCREMENTAL_BY_PARTITION] = ModelKindName.INCREMENTAL_BY_PARTITION
592    forward_only: t.Literal[True] = True
593    disable_restatement: SQLGlotBool = False
594
595    @field_validator("forward_only", mode="before")
596    def _forward_only_validator(cls, v: t.Union[bool, exp.Expr]) -> t.Literal[True]:
597        if v is not True:
598            raise ConfigError(
599                "Do not specify the `forward_only` configuration key - INCREMENTAL_BY_PARTITION models are always forward_only."
600            )
601        return v
602
603    @property
604    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
605        return [
606            *super().metadata_hash_values,
607            str(self.forward_only),
608            str(self.disable_restatement),
609        ]
610
611    def to_expression(
612        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
613    ) -> d.ModelKind:
614        return super().to_expression(
615            expressions=[
616                *(expressions or []),
617                *_properties(
618                    {
619                        "forward_only": self.forward_only,
620                        "disable_restatement": self.disable_restatement,
621                    }
622                ),
623            ],
624        )

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
name: Literal[INCREMENTAL_BY_PARTITION]
forward_only: Literal[True]
disable_restatement: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x7a2adca284c0>, json_schema_input_type=PydanticUndefined)]
metadata_hash_values: List[Optional[str]]
603    @property
604    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
605        return [
606            *super().metadata_hash_values,
607            str(self.forward_only),
608            str(self.disable_restatement),
609        ]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.core.Expr]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
611    def to_expression(
612        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
613    ) -> d.ModelKind:
614        return super().to_expression(
615            expressions=[
616                *(expressions or []),
617                *_properties(
618                    {
619                        "forward_only": self.forward_only,
620                        "disable_restatement": self.disable_restatement,
621                    }
622                ),
623            ],
624        )
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].

class IncrementalUnmanagedKind(_Incremental):
627class IncrementalUnmanagedKind(_Incremental):
628    name: t.Literal[ModelKindName.INCREMENTAL_UNMANAGED] = ModelKindName.INCREMENTAL_UNMANAGED
629    insert_overwrite: SQLGlotBool = False
630    forward_only: SQLGlotBool = True
631    disable_restatement: SQLGlotBool = True
632
633    @property
634    def data_hash_values(self) -> t.List[t.Optional[str]]:
635        return [*super().data_hash_values, str(self.insert_overwrite)]
636
637    @property
638    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
639        return [
640            *super().metadata_hash_values,
641            str(self.forward_only),
642            str(self.disable_restatement),
643        ]
644
645    def to_expression(
646        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
647    ) -> d.ModelKind:
648        return super().to_expression(
649            expressions=[
650                *(expressions or []),
651                *_properties(
652                    {
653                        "insert_overwrite": self.insert_overwrite,
654                        "forward_only": self.forward_only,
655                        "disable_restatement": self.disable_restatement,
656                    }
657                ),
658            ],
659        )

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
name: Literal[INCREMENTAL_UNMANAGED]
insert_overwrite: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x7a2adca284c0>, json_schema_input_type=PydanticUndefined)]
forward_only: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x7a2adca284c0>, json_schema_input_type=PydanticUndefined)]
disable_restatement: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x7a2adca284c0>, json_schema_input_type=PydanticUndefined)]
data_hash_values: List[Optional[str]]
633    @property
634    def data_hash_values(self) -> t.List[t.Optional[str]]:
635        return [*super().data_hash_values, str(self.insert_overwrite)]
metadata_hash_values: List[Optional[str]]
637    @property
638    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
639        return [
640            *super().metadata_hash_values,
641            str(self.forward_only),
642            str(self.disable_restatement),
643        ]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.core.Expr]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
645    def to_expression(
646        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
647    ) -> d.ModelKind:
648        return super().to_expression(
649            expressions=[
650                *(expressions or []),
651                *_properties(
652                    {
653                        "insert_overwrite": self.insert_overwrite,
654                        "forward_only": self.forward_only,
655                        "disable_restatement": self.disable_restatement,
656                    }
657                ),
658            ],
659        )
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
_Incremental
on_destructive_change
on_additive_change
auto_restatement_cron
_ModelKind
model_kind_name
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
ModelKindMixin
is_incremental_by_time_range
is_incremental_by_unique_key
is_incremental_by_partition
is_incremental_unmanaged
is_incremental
is_full
is_view
is_embedded
is_seed
is_external
is_scd_type_2
is_scd_type_2_by_time
is_scd_type_2_by_column
is_custom
is_managed
is_dbt_custom
is_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_python_models
supports_grants
class ViewKind(_ModelKind):
662class ViewKind(_ModelKind):
663    name: t.Literal[ModelKindName.VIEW] = ModelKindName.VIEW
664    materialized: SQLGlotBool = False
665
666    @property
667    def data_hash_values(self) -> t.List[t.Optional[str]]:
668        return [*super().data_hash_values, str(self.materialized)]
669
670    @property
671    def supports_python_models(self) -> bool:
672        return False
673
674    def to_expression(
675        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
676    ) -> d.ModelKind:
677        return super().to_expression(
678            expressions=[
679                *(expressions or []),
680                _property("materialized", self.materialized),
681            ],
682        )

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
name: Literal[VIEW]
materialized: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x7a2adca284c0>, json_schema_input_type=PydanticUndefined)]
data_hash_values: List[Optional[str]]
666    @property
667    def data_hash_values(self) -> t.List[t.Optional[str]]:
668        return [*super().data_hash_values, str(self.materialized)]
supports_python_models: bool
670    @property
671    def supports_python_models(self) -> bool:
672        return False
def to_expression( self, expressions: Optional[List[sqlglot.expressions.core.Expr]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
674    def to_expression(
675        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
676    ) -> d.ModelKind:
677        return super().to_expression(
678            expressions=[
679                *(expressions or []),
680                _property("materialized", self.materialized),
681            ],
682        )
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
_ModelKind
model_kind_name
metadata_hash_values
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
ModelKindMixin
is_incremental_by_time_range
is_incremental_by_unique_key
is_incremental_by_partition
is_incremental_unmanaged
is_incremental
is_full
is_view
is_embedded
is_seed
is_external
is_scd_type_2
is_scd_type_2_by_time
is_scd_type_2_by_column
is_custom
is_managed
is_dbt_custom
is_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_grants
class SeedKind(_ModelKind):
685class SeedKind(_ModelKind):
686    name: t.Literal[ModelKindName.SEED] = ModelKindName.SEED
687    path: SQLGlotString
688    batch_size: SQLGlotPositiveInt = 1000
689    csv_settings: t.Optional[CsvSettings] = None
690
691    @field_validator("csv_settings", mode="before")
692    @classmethod
693    def _parse_csv_settings(cls, v: t.Any) -> t.Optional[CsvSettings]:
694        if v is None or isinstance(v, CsvSettings):
695            return v
696        if isinstance(v, exp.Expr):
697            tuple_exp = parse_properties(cls, v, None)
698            if not tuple_exp:
699                return None
700            return CsvSettings(**{e.left.name: e.right for e in tuple_exp.expressions})
701        if isinstance(v, dict):
702            return CsvSettings(**v)
703        return v
704
705    def to_expression(
706        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
707    ) -> d.ModelKind:
708        """Convert the seed kind into a SQLGlot expression."""
709        return super().to_expression(
710            expressions=[
711                *(expressions or []),
712                *_properties(
713                    {
714                        "path": exp.Literal.string(self.path),
715                        "batch_size": self.batch_size,
716                    }
717                ),
718            ],
719        )
720
721    @property
722    def data_hash_values(self) -> t.List[t.Optional[str]]:
723        csv_setting_values = (self.csv_settings or CsvSettings()).dict().values()
724        return [
725            *super().data_hash_values,
726            *(v if isinstance(v, (str, type(None))) else str(v) for v in csv_setting_values),
727        ]
728
729    @property
730    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
731        return [*super().metadata_hash_values, str(self.batch_size)]
732
733    @property
734    def supports_python_models(self) -> bool:
735        return False

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
name: Literal[SEED]
path: typing.Annotated[str, BeforeValidator(func=<function validate_string at 0x7a2adca283a0>, json_schema_input_type=PydanticUndefined)]
batch_size: typing.Annotated[int, BeforeValidator(func=<function positive_int_validator at 0x7a2adca28550>, json_schema_input_type=PydanticUndefined)]
csv_settings: Optional[sqlmesh.core.model.seed.CsvSettings]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.core.Expr]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
705    def to_expression(
706        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
707    ) -> d.ModelKind:
708        """Convert the seed kind into a SQLGlot expression."""
709        return super().to_expression(
710            expressions=[
711                *(expressions or []),
712                *_properties(
713                    {
714                        "path": exp.Literal.string(self.path),
715                        "batch_size": self.batch_size,
716                    }
717                ),
718            ],
719        )

Convert the seed kind into a SQLGlot expression.

data_hash_values: List[Optional[str]]
721    @property
722    def data_hash_values(self) -> t.List[t.Optional[str]]:
723        csv_setting_values = (self.csv_settings or CsvSettings()).dict().values()
724        return [
725            *super().data_hash_values,
726            *(v if isinstance(v, (str, type(None))) else str(v) for v in csv_setting_values),
727        ]
metadata_hash_values: List[Optional[str]]
729    @property
730    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
731        return [*super().metadata_hash_values, str(self.batch_size)]
supports_python_models: bool
733    @property
734    def supports_python_models(self) -> bool:
735        return False
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
_ModelKind
model_kind_name
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
ModelKindMixin
is_incremental_by_time_range
is_incremental_by_unique_key
is_incremental_by_partition
is_incremental_unmanaged
is_incremental
is_full
is_view
is_embedded
is_seed
is_external
is_scd_type_2
is_scd_type_2_by_time
is_scd_type_2_by_column
is_custom
is_managed
is_dbt_custom
is_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_grants
class FullKind(_ModelKind):
738class FullKind(_ModelKind):
739    name: t.Literal[ModelKindName.FULL] = ModelKindName.FULL

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
name: Literal[FULL]
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
_ModelKind
model_kind_name
to_expression
data_hash_values
metadata_hash_values
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
ModelKindMixin
is_incremental_by_time_range
is_incremental_by_unique_key
is_incremental_by_partition
is_incremental_unmanaged
is_incremental
is_full
is_view
is_embedded
is_seed
is_external
is_scd_type_2
is_scd_type_2_by_time
is_scd_type_2_by_column
is_custom
is_managed
is_dbt_custom
is_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_python_models
supports_grants
class SCDType2ByTimeKind(_SCDType2Kind):
824class SCDType2ByTimeKind(_SCDType2Kind):
825    name: t.Literal[ModelKindName.SCD_TYPE_2, ModelKindName.SCD_TYPE_2_BY_TIME] = (
826        ModelKindName.SCD_TYPE_2_BY_TIME
827    )
828    updated_at_name: SQLGlotColumn = Field(exp.column("updated_at"), validate_default=True)
829    updated_at_as_valid_from: SQLGlotBool = False
830
831    _always_validate_updated_at = field_validator("updated_at_name", mode="before")(
832        column_validator
833    )
834
835    @property
836    def data_hash_values(self) -> t.List[t.Optional[str]]:
837        return [
838            *super().data_hash_values,
839            gen(self.updated_at_name),
840            str(self.updated_at_as_valid_from),
841        ]
842
843    def to_expression(
844        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
845    ) -> d.ModelKind:
846        return super().to_expression(
847            expressions=[
848                *(expressions or []),
849                *_properties(
850                    {
851                        "updated_at_name": self.updated_at_name,
852                        "updated_at_as_valid_from": self.updated_at_as_valid_from,
853                    }
854                ),
855            ],
856        )

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
name: Literal[SCD_TYPE_2, SCD_TYPE_2_BY_TIME]
updated_at_name: typing.Annotated[sqlglot.expressions.core.Expr, BeforeValidator(func=<function column_validator at 0x7a2adca288b0>, json_schema_input_type=PydanticUndefined)]
updated_at_as_valid_from: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x7a2adca284c0>, json_schema_input_type=PydanticUndefined)]
data_hash_values: List[Optional[str]]
835    @property
836    def data_hash_values(self) -> t.List[t.Optional[str]]:
837        return [
838            *super().data_hash_values,
839            gen(self.updated_at_name),
840            str(self.updated_at_as_valid_from),
841        ]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.core.Expr]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
843    def to_expression(
844        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
845    ) -> d.ModelKind:
846        return super().to_expression(
847            expressions=[
848                *(expressions or []),
849                *_properties(
850                    {
851                        "updated_at_name": self.updated_at_name,
852                        "updated_at_as_valid_from": self.updated_at_as_valid_from,
853                    }
854                ),
855            ],
856        )
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].

class SCDType2ByColumnKind(_SCDType2Kind):
859class SCDType2ByColumnKind(_SCDType2Kind):
860    name: t.Literal[ModelKindName.SCD_TYPE_2_BY_COLUMN] = ModelKindName.SCD_TYPE_2_BY_COLUMN
861    columns: SQLGlotListOfFieldsOrStar
862    execution_time_as_valid_from: SQLGlotBool = False
863    updated_at_name: t.Optional[SQLGlotColumn] = None
864
865    @property
866    def data_hash_values(self) -> t.List[t.Optional[str]]:
867        columns_sql = (
868            [gen(c) for c in self.columns]
869            if isinstance(self.columns, list)
870            else [gen(self.columns)]
871        )
872        return [
873            *super().data_hash_values,
874            *columns_sql,
875            str(self.execution_time_as_valid_from),
876            gen(self.updated_at_name) if self.updated_at_name is not None else None,
877        ]
878
879    def to_expression(
880        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
881    ) -> d.ModelKind:
882        return super().to_expression(
883            expressions=[
884                *(expressions or []),
885                *_properties(
886                    {
887                        "columns": exp.Tuple(expressions=self.columns)
888                        if isinstance(self.columns, list)
889                        else self.columns,
890                        "execution_time_as_valid_from": self.execution_time_as_valid_from,
891                    }
892                ),
893            ],
894        )

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
name: Literal[SCD_TYPE_2_BY_COLUMN]
columns: Annotated[Union[Annotated[List[sqlglot.expressions.core.Expr], BeforeValidator(func=<function list_of_fields_validator at 0x7a2adca28820>, json_schema_input_type=PydanticUndefined)], sqlglot.expressions.core.Star], BeforeValidator(func=<function list_of_fields_or_star_validator at 0x7a2adca28940>, json_schema_input_type=PydanticUndefined)]
execution_time_as_valid_from: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x7a2adca284c0>, json_schema_input_type=PydanticUndefined)]
updated_at_name: Optional[Annotated[sqlglot.expressions.core.Expr, BeforeValidator(func=<function column_validator at 0x7a2adca288b0>, json_schema_input_type=PydanticUndefined)]]
data_hash_values: List[Optional[str]]
865    @property
866    def data_hash_values(self) -> t.List[t.Optional[str]]:
867        columns_sql = (
868            [gen(c) for c in self.columns]
869            if isinstance(self.columns, list)
870            else [gen(self.columns)]
871        )
872        return [
873            *super().data_hash_values,
874            *columns_sql,
875            str(self.execution_time_as_valid_from),
876            gen(self.updated_at_name) if self.updated_at_name is not None else None,
877        ]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.core.Expr]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
879    def to_expression(
880        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
881    ) -> d.ModelKind:
882        return super().to_expression(
883            expressions=[
884                *(expressions or []),
885                *_properties(
886                    {
887                        "columns": exp.Tuple(expressions=self.columns)
888                        if isinstance(self.columns, list)
889                        else self.columns,
890                        "execution_time_as_valid_from": self.execution_time_as_valid_from,
891                    }
892                ),
893            ],
894        )
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].

class ManagedKind(_ModelKind):
897class ManagedKind(_ModelKind):
898    name: t.Literal[ModelKindName.MANAGED] = ModelKindName.MANAGED
899    disable_restatement: t.Literal[True] = True
900
901    @property
902    def supports_python_models(self) -> bool:
903        return False

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
name: Literal[MANAGED]
disable_restatement: Literal[True]
supports_python_models: bool
901    @property
902    def supports_python_models(self) -> bool:
903        return False
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
_ModelKind
model_kind_name
to_expression
data_hash_values
metadata_hash_values
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
ModelKindMixin
is_incremental_by_time_range
is_incremental_by_unique_key
is_incremental_by_partition
is_incremental_unmanaged
is_incremental
is_full
is_view
is_embedded
is_seed
is_external
is_scd_type_2
is_scd_type_2_by_time
is_scd_type_2_by_column
is_custom
is_managed
is_dbt_custom
is_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_grants
class DbtCustomKind(_ModelKind):
906class DbtCustomKind(_ModelKind):
907    name: t.Literal[ModelKindName.DBT_CUSTOM] = ModelKindName.DBT_CUSTOM
908    materialization: str
909    adapter: str = "default"
910    definition: str
911    dialect: t.Optional[str] = Field(None, validate_default=True)
912
913    _dialect_validator = kind_dialect_validator
914
915    @field_validator("materialization", "adapter", "definition", mode="before")
916    @classmethod
917    def _validate_fields(cls, v: t.Any) -> str:
918        return validate_string(v)
919
920    @property
921    def data_hash_values(self) -> t.List[t.Optional[str]]:
922        return [
923            *super().data_hash_values,
924            self.materialization,
925            self.definition,
926            self.adapter,
927            self.dialect,
928        ]
929
930    def to_expression(
931        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
932    ) -> d.ModelKind:
933        return super().to_expression(
934            expressions=[
935                *(expressions or []),
936                *_properties(
937                    {
938                        "materialization": exp.Literal.string(self.materialization),
939                        "adapter": exp.Literal.string(self.adapter),
940                    }
941                ),
942            ],
943        )

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
name: Literal[DBT_CUSTOM]
materialization: str
adapter: str
definition: str
dialect: Optional[str]
data_hash_values: List[Optional[str]]
920    @property
921    def data_hash_values(self) -> t.List[t.Optional[str]]:
922        return [
923            *super().data_hash_values,
924            self.materialization,
925            self.definition,
926            self.adapter,
927            self.dialect,
928        ]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.core.Expr]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
930    def to_expression(
931        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
932    ) -> d.ModelKind:
933        return super().to_expression(
934            expressions=[
935                *(expressions or []),
936                *_properties(
937                    {
938                        "materialization": exp.Literal.string(self.materialization),
939                        "adapter": exp.Literal.string(self.adapter),
940                    }
941                ),
942            ],
943        )
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
_ModelKind
model_kind_name
metadata_hash_values
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
ModelKindMixin
is_incremental_by_time_range
is_incremental_by_unique_key
is_incremental_by_partition
is_incremental_unmanaged
is_incremental
is_full
is_view
is_embedded
is_seed
is_external
is_scd_type_2
is_scd_type_2_by_time
is_scd_type_2_by_column
is_custom
is_managed
is_dbt_custom
is_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_python_models
supports_grants
class EmbeddedKind(_ModelKind):
946class EmbeddedKind(_ModelKind):
947    name: t.Literal[ModelKindName.EMBEDDED] = ModelKindName.EMBEDDED
948
949    @property
950    def supports_python_models(self) -> bool:
951        return False

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
name: Literal[EMBEDDED]
supports_python_models: bool
949    @property
950    def supports_python_models(self) -> bool:
951        return False
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
_ModelKind
model_kind_name
to_expression
data_hash_values
metadata_hash_values
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
ModelKindMixin
is_incremental_by_time_range
is_incremental_by_unique_key
is_incremental_by_partition
is_incremental_unmanaged
is_incremental
is_full
is_view
is_embedded
is_seed
is_external
is_scd_type_2
is_scd_type_2_by_time
is_scd_type_2_by_column
is_custom
is_managed
is_dbt_custom
is_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_grants
class ExternalKind(_ModelKind):
954class ExternalKind(_ModelKind):
955    name: t.Literal[ModelKindName.EXTERNAL] = ModelKindName.EXTERNAL

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
name: Literal[EXTERNAL]
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
_ModelKind
model_kind_name
to_expression
data_hash_values
metadata_hash_values
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
ModelKindMixin
is_incremental_by_time_range
is_incremental_by_unique_key
is_incremental_by_partition
is_incremental_unmanaged
is_incremental
is_full
is_view
is_embedded
is_seed
is_external
is_scd_type_2
is_scd_type_2_by_time
is_scd_type_2_by_column
is_custom
is_managed
is_dbt_custom
is_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_python_models
supports_grants
class CustomKind(_ModelKind):
 958class CustomKind(_ModelKind):
 959    name: t.Literal[ModelKindName.CUSTOM] = ModelKindName.CUSTOM
 960    materialization: str
 961    materialization_properties_: t.Optional[exp.Tuple] = Field(
 962        default=None, alias="materialization_properties"
 963    )
 964    forward_only: SQLGlotBool = False
 965    disable_restatement: SQLGlotBool = False
 966    batch_size: t.Optional[SQLGlotPositiveInt] = None
 967    batch_concurrency: t.Optional[SQLGlotPositiveInt] = None
 968    lookback: t.Optional[SQLGlotPositiveInt] = None
 969    auto_restatement_cron: t.Optional[SQLGlotCron] = None
 970    auto_restatement_intervals: t.Optional[SQLGlotPositiveInt] = None
 971
 972    # so that CustomKind subclasses know the dialect when validating / normalizing / interpreting values in `materialization_properties`
 973    dialect: str = Field(exclude=True)
 974
 975    _properties_validator = properties_validator
 976
 977    @field_validator("materialization", mode="before")
 978    @classmethod
 979    def _validate_materialization(cls, v: t.Any) -> str:
 980        # note: create_model_kind() validates the custom materialization class
 981        return validate_string(v)
 982
 983    @property
 984    def materialization_properties(self) -> CustomMaterializationProperties:
 985        """A dictionary of materialization properties."""
 986        if not self.materialization_properties_:
 987            return {}
 988        return d.interpret_key_value_pairs(self.materialization_properties_)
 989
 990    @property
 991    def data_hash_values(self) -> t.List[t.Optional[str]]:
 992        return [
 993            *super().data_hash_values,
 994            self.materialization,
 995            gen(self.materialization_properties_) if self.materialization_properties_ else None,
 996            str(self.lookback) if self.lookback is not None else None,
 997        ]
 998
 999    @property
1000    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
1001        return [
1002            *super().metadata_hash_values,
1003            str(self.batch_size) if self.batch_size is not None else None,
1004            str(self.batch_concurrency) if self.batch_concurrency is not None else None,
1005            str(self.forward_only),
1006            str(self.disable_restatement),
1007            self.auto_restatement_cron,
1008            str(self.auto_restatement_intervals)
1009            if self.auto_restatement_intervals is not None
1010            else None,
1011        ]
1012
1013    def to_expression(
1014        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
1015    ) -> d.ModelKind:
1016        return super().to_expression(
1017            expressions=[
1018                *(expressions or []),
1019                *_properties(
1020                    {
1021                        "materialization": exp.Literal.string(self.materialization),
1022                        "materialization_properties": self.materialization_properties_,
1023                        "forward_only": self.forward_only,
1024                        "disable_restatement": self.disable_restatement,
1025                        "batch_size": self.batch_size,
1026                        "batch_concurrency": self.batch_concurrency,
1027                        "lookback": self.lookback,
1028                        "auto_restatement_cron": self.auto_restatement_cron,
1029                        "auto_restatement_intervals": self.auto_restatement_intervals,
1030                    }
1031                ),
1032            ],
1033        )

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
name: Literal[CUSTOM]
materialization: str
materialization_properties_: Optional[sqlglot.expressions.query.Tuple]
forward_only: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x7a2adca284c0>, json_schema_input_type=PydanticUndefined)]
disable_restatement: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x7a2adca284c0>, json_schema_input_type=PydanticUndefined)]
batch_size: Optional[Annotated[int, BeforeValidator(func=<function positive_int_validator at 0x7a2adca28550>, json_schema_input_type=PydanticUndefined)]]
batch_concurrency: Optional[Annotated[int, BeforeValidator(func=<function positive_int_validator at 0x7a2adca28550>, json_schema_input_type=PydanticUndefined)]]
lookback: Optional[Annotated[int, BeforeValidator(func=<function positive_int_validator at 0x7a2adca28550>, json_schema_input_type=PydanticUndefined)]]
auto_restatement_cron: Optional[Annotated[str, BeforeValidator(func=<function cron_validator at 0x7a2adca289d0>, json_schema_input_type=PydanticUndefined)]]
auto_restatement_intervals: Optional[Annotated[int, BeforeValidator(func=<function positive_int_validator at 0x7a2adca28550>, json_schema_input_type=PydanticUndefined)]]
dialect: str
materialization_properties: Dict[str, sqlglot.expressions.core.Expr | str | int | float | bool]
983    @property
984    def materialization_properties(self) -> CustomMaterializationProperties:
985        """A dictionary of materialization properties."""
986        if not self.materialization_properties_:
987            return {}
988        return d.interpret_key_value_pairs(self.materialization_properties_)

A dictionary of materialization properties.

data_hash_values: List[Optional[str]]
990    @property
991    def data_hash_values(self) -> t.List[t.Optional[str]]:
992        return [
993            *super().data_hash_values,
994            self.materialization,
995            gen(self.materialization_properties_) if self.materialization_properties_ else None,
996            str(self.lookback) if self.lookback is not None else None,
997        ]
metadata_hash_values: List[Optional[str]]
 999    @property
1000    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
1001        return [
1002            *super().metadata_hash_values,
1003            str(self.batch_size) if self.batch_size is not None else None,
1004            str(self.batch_concurrency) if self.batch_concurrency is not None else None,
1005            str(self.forward_only),
1006            str(self.disable_restatement),
1007            self.auto_restatement_cron,
1008            str(self.auto_restatement_intervals)
1009            if self.auto_restatement_intervals is not None
1010            else None,
1011        ]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.core.Expr]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
1013    def to_expression(
1014        self, expressions: t.Optional[t.List[exp.Expr]] = None, **kwargs: t.Any
1015    ) -> d.ModelKind:
1016        return super().to_expression(
1017            expressions=[
1018                *(expressions or []),
1019                *_properties(
1020                    {
1021                        "materialization": exp.Literal.string(self.materialization),
1022                        "materialization_properties": self.materialization_properties_,
1023                        "forward_only": self.forward_only,
1024                        "disable_restatement": self.disable_restatement,
1025                        "batch_size": self.batch_size,
1026                        "batch_concurrency": self.batch_concurrency,
1027                        "lookback": self.lookback,
1028                        "auto_restatement_cron": self.auto_restatement_cron,
1029                        "auto_restatement_intervals": self.auto_restatement_intervals,
1030                    }
1031                ),
1032            ],
1033        )
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
_ModelKind
model_kind_name
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
ModelKindMixin
is_incremental_by_time_range
is_incremental_by_unique_key
is_incremental_by_partition
is_incremental_unmanaged
is_incremental
is_full
is_view
is_embedded
is_seed
is_external
is_scd_type_2
is_scd_type_2_by_time
is_scd_type_2_by_column
is_custom
is_managed
is_dbt_custom
is_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_python_models
supports_grants
MODEL_KIND_NAME_TO_TYPE: Dict[str, Type[Annotated[Union[EmbeddedKind, ExternalKind, FullKind, IncrementalByTimeRangeKind, IncrementalByUniqueKeyKind, IncrementalByPartitionKind, IncrementalUnmanagedKind, SeedKind, ViewKind, SCDType2ByTimeKind, SCDType2ByColumnKind, CustomKind, ManagedKind, DbtCustomKind], FieldInfo(annotation=NoneType, required=True, discriminator='name')]]] = {EMBEDDED: <class 'EmbeddedKind'>, EXTERNAL: <class 'ExternalKind'>, FULL: <class 'FullKind'>, INCREMENTAL_BY_TIME_RANGE: <class 'IncrementalByTimeRangeKind'>, INCREMENTAL_BY_UNIQUE_KEY: <class 'IncrementalByUniqueKeyKind'>, INCREMENTAL_BY_PARTITION: <class 'IncrementalByPartitionKind'>, INCREMENTAL_UNMANAGED: <class 'IncrementalUnmanagedKind'>, SEED: <class 'SeedKind'>, VIEW: <class 'ViewKind'>, SCD_TYPE_2: <class 'SCDType2ByTimeKind'>, SCD_TYPE_2_BY_TIME: <class 'SCDType2ByTimeKind'>, SCD_TYPE_2_BY_COLUMN: <class 'SCDType2ByColumnKind'>, CUSTOM: <class 'CustomKind'>, MANAGED: <class 'ManagedKind'>, DBT_CUSTOM: <class 'DbtCustomKind'>}
def model_kind_type_from_name( name: Optional[str]) -> Type[Annotated[Union[EmbeddedKind, ExternalKind, FullKind, IncrementalByTimeRangeKind, IncrementalByUniqueKeyKind, IncrementalByPartitionKind, IncrementalUnmanagedKind, SeedKind, ViewKind, SCDType2ByTimeKind, SCDType2ByColumnKind, CustomKind, ManagedKind, DbtCustomKind], FieldInfo(annotation=NoneType, required=True, discriminator='name')]]:
1075def model_kind_type_from_name(name: t.Optional[str]) -> t.Type[ModelKind]:
1076    klass = MODEL_KIND_NAME_TO_TYPE.get(name) if name else None
1077    if not klass:
1078        raise ConfigError(f"Invalid model kind '{name}'")
1079    return t.cast(t.Type[ModelKind], klass)
def create_model_kind( v: Any, dialect: str, defaults: Dict[str, Any]) -> Annotated[Union[EmbeddedKind, ExternalKind, FullKind, IncrementalByTimeRangeKind, IncrementalByUniqueKeyKind, IncrementalByPartitionKind, IncrementalUnmanagedKind, SeedKind, ViewKind, SCDType2ByTimeKind, SCDType2ByColumnKind, CustomKind, ManagedKind, DbtCustomKind], FieldInfo(annotation=NoneType, required=True, discriminator='name')]:
1082def create_model_kind(v: t.Any, dialect: str, defaults: t.Dict[str, t.Any]) -> ModelKind:
1083    if isinstance(v, _ModelKind):
1084        return t.cast(ModelKind, v)
1085
1086    if isinstance(v, (d.ModelKind, dict)):
1087        props = (
1088            {prop.name: prop.args.get("value") for prop in v.expressions}
1089            if isinstance(v, d.ModelKind)
1090            else v
1091        )
1092        name = v.this if isinstance(v, d.ModelKind) else props.get("name")
1093
1094        # We want to ensure whatever name is provided to construct the class is the same name that will be
1095        # found inside the class itself in order to avoid a change during plan/apply for legacy aliases.
1096        # Ex: Pass in `SCD_TYPE_2` then we want to ensure we get `SCD_TYPE_2` as the kind name
1097        # instead of `SCD_TYPE_2_BY_TIME`.
1098        props["name"] = name
1099        kind_type = model_kind_type_from_name(name)
1100
1101        if "dialect" in kind_type.all_fields() and props.get("dialect") is None:
1102            props["dialect"] = dialect
1103
1104        # only pass the on_destructive_change or on_additive_change user default to models inheriting from _Incremental
1105        # that don't explicitly set it in the model definition
1106        if issubclass(kind_type, _Incremental):
1107            for on_change_property in ("on_additive_change", "on_destructive_change"):
1108                if (
1109                    props.get(on_change_property) is None
1110                    and defaults.get(on_change_property) is not None
1111                ):
1112                    props[on_change_property] = defaults.get(on_change_property)
1113
1114        # only pass the batch_concurrency user default to models inheriting from _IncrementalBy
1115        # that don't explicitly set it in the model definition, but ignore subclasses of _IncrementalBy
1116        # that hardcode a specific batch_concurrency
1117        if issubclass(kind_type, _IncrementalBy):
1118            BATCH_CONCURRENCY: t.Final = "batch_concurrency"
1119            if (
1120                props.get(BATCH_CONCURRENCY) is None
1121                and defaults.get(BATCH_CONCURRENCY) is not None
1122                and kind_type.all_field_infos()[BATCH_CONCURRENCY].default is None
1123            ):
1124                props[BATCH_CONCURRENCY] = defaults.get(BATCH_CONCURRENCY)
1125
1126        if kind_type == CustomKind:
1127            # load the custom materialization class and check if it uses a custom kind type
1128            from sqlmesh.core.snapshot.evaluator import get_custom_materialization_type
1129
1130            if "materialization" not in props:
1131                raise ConfigError(
1132                    "The 'materialization' property is required for models of the CUSTOM kind"
1133                )
1134
1135            # The below call will print a warning if a materialization with the given name doesn't exist
1136            # we dont want to throw an error here because we still want Models with a CustomKind to be able
1137            # to be serialized / deserialized in contexts where the custom materialization class may not be available,
1138            # such as in HTTP request handlers
1139            custom_materialization = get_custom_materialization_type(
1140                validate_string(props.get("materialization")), raise_errors=False
1141            )
1142            if custom_materialization is not None:
1143                actual_kind_type, _ = custom_materialization
1144                return actual_kind_type(**props)
1145
1146        validate_extra_and_required_fields(
1147            kind_type, set(props), f"MODEL block 'kind {name}' field"
1148        )
1149        return kind_type(**props)
1150
1151    name = (v.name if isinstance(v, exp.Expr) else str(v)).upper()
1152    return model_kind_type_from_name(name)(name=name)  # type: ignore
def model_kind_validator( cls: Type, v: Any, info: Optional[pydantic_core.core_schema.ValidationInfo]) -> Annotated[Union[EmbeddedKind, ExternalKind, FullKind, IncrementalByTimeRangeKind, IncrementalByUniqueKeyKind, IncrementalByPartitionKind, IncrementalUnmanagedKind, SeedKind, ViewKind, SCDType2ByTimeKind, SCDType2ByColumnKind, CustomKind, ManagedKind, DbtCustomKind], FieldInfo(annotation=NoneType, required=True, discriminator='name')]:
1155def _model_kind_validator(cls: t.Type, v: t.Any, info: t.Optional[ValidationInfo]) -> ModelKind:
1156    dialect = get_dialect(info.data) if info else ""
1157    return create_model_kind(v, dialect, {})

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.