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

Returns the model kind name.

is_incremental_by_time_range: bool
48    @property
49    def is_incremental_by_time_range(self) -> bool:
50        return self.model_kind_name == ModelKindName.INCREMENTAL_BY_TIME_RANGE
is_incremental_by_unique_key: bool
52    @property
53    def is_incremental_by_unique_key(self) -> bool:
54        return self.model_kind_name == ModelKindName.INCREMENTAL_BY_UNIQUE_KEY
is_incremental_by_partition: bool
56    @property
57    def is_incremental_by_partition(self) -> bool:
58        return self.model_kind_name == ModelKindName.INCREMENTAL_BY_PARTITION
is_incremental_unmanaged: bool
60    @property
61    def is_incremental_unmanaged(self) -> bool:
62        return self.model_kind_name == ModelKindName.INCREMENTAL_UNMANAGED
is_incremental: bool
64    @property
65    def is_incremental(self) -> bool:
66        return (
67            self.is_incremental_by_time_range
68            or self.is_incremental_by_unique_key
69            or self.is_incremental_by_partition
70            or self.is_incremental_unmanaged
71            or self.is_scd_type_2
72        )
is_full: bool
74    @property
75    def is_full(self) -> bool:
76        return self.model_kind_name == ModelKindName.FULL
is_view: bool
78    @property
79    def is_view(self) -> bool:
80        return self.model_kind_name == ModelKindName.VIEW
is_embedded: bool
82    @property
83    def is_embedded(self) -> bool:
84        return self.model_kind_name == ModelKindName.EMBEDDED
is_seed: bool
86    @property
87    def is_seed(self) -> bool:
88        return self.model_kind_name == ModelKindName.SEED
is_external: bool
90    @property
91    def is_external(self) -> bool:
92        return self.model_kind_name == ModelKindName.EXTERNAL
is_scd_type_2: bool
 94    @property
 95    def is_scd_type_2(self) -> bool:
 96        return self.model_kind_name in {
 97            ModelKindName.SCD_TYPE_2,
 98            ModelKindName.SCD_TYPE_2_BY_TIME,
 99            ModelKindName.SCD_TYPE_2_BY_COLUMN,
100        }
is_scd_type_2_by_time: bool
102    @property
103    def is_scd_type_2_by_time(self) -> bool:
104        return self.model_kind_name in {ModelKindName.SCD_TYPE_2, ModelKindName.SCD_TYPE_2_BY_TIME}
is_scd_type_2_by_column: bool
106    @property
107    def is_scd_type_2_by_column(self) -> bool:
108        return self.model_kind_name == ModelKindName.SCD_TYPE_2_BY_COLUMN
is_custom: bool
110    @property
111    def is_custom(self) -> bool:
112        return self.model_kind_name == ModelKindName.CUSTOM
is_managed: bool
114    @property
115    def is_managed(self) -> bool:
116        return self.model_kind_name == ModelKindName.MANAGED
is_symbolic: bool
118    @property
119    def is_symbolic(self) -> bool:
120        """A symbolic model is one that doesn't execute at all."""
121        return self.model_kind_name in (ModelKindName.EMBEDDED, ModelKindName.EXTERNAL)

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

is_materialized: bool
123    @property
124    def is_materialized(self) -> bool:
125        return self.model_kind_name is not None and not (self.is_symbolic or self.is_view)
only_execution_time: bool
127    @property
128    def only_execution_time(self) -> bool:
129        """Whether or not this model only cares about execution time to render."""
130        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
132    @property
133    def full_history_restatement_only(self) -> bool:
134        """Whether or not this model only supports restatement of full history."""
135        return (
136            self.is_incremental_unmanaged
137            or self.is_incremental_by_unique_key
138            or self.is_incremental_by_partition
139            or self.is_scd_type_2
140            or self.is_managed
141            or self.is_full
142            or self.is_view
143        )

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

supports_python_models: bool
145    @property
146    def supports_python_models(self) -> bool:
147        return True
class ModelKindName(builtins.str, ModelKindMixin, enum.Enum):
150class ModelKindName(str, ModelKindMixin, Enum):
151    """The kind of model, determining how this data is computed and stored in the warehouse."""
152
153    INCREMENTAL_BY_TIME_RANGE = "INCREMENTAL_BY_TIME_RANGE"
154    INCREMENTAL_BY_UNIQUE_KEY = "INCREMENTAL_BY_UNIQUE_KEY"
155    INCREMENTAL_BY_PARTITION = "INCREMENTAL_BY_PARTITION"
156    INCREMENTAL_UNMANAGED = "INCREMENTAL_UNMANAGED"
157    FULL = "FULL"
158    # Legacy alias to SCD Type 2 By Time
159    # Only used for Parsing and mapping name to SCD Type 2 By Time
160    SCD_TYPE_2 = "SCD_TYPE_2"
161    SCD_TYPE_2_BY_TIME = "SCD_TYPE_2_BY_TIME"
162    SCD_TYPE_2_BY_COLUMN = "SCD_TYPE_2_BY_COLUMN"
163    VIEW = "VIEW"
164    EMBEDDED = "EMBEDDED"
165    SEED = "SEED"
166    EXTERNAL = "EXTERNAL"
167    CUSTOM = "CUSTOM"
168    MANAGED = "MANAGED"
169
170    @property
171    def model_kind_name(self) -> t.Optional[ModelKindName]:
172        return self
173
174    def __str__(self) -> str:
175        return self.name
176
177    def __repr__(self) -> str:
178        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
model_kind_name: Optional[ModelKindName]
170    @property
171    def model_kind_name(self) -> t.Optional[ModelKindName]:
172        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_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_python_models
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):
181class OnDestructiveChange(str, Enum):
182    """What should happen when a forward-only model change requires a destructive schema change."""
183
184    ERROR = "ERROR"
185    WARN = "WARN"
186    ALLOW = "ALLOW"
187
188    @property
189    def is_error(self) -> bool:
190        return self == OnDestructiveChange.ERROR
191
192    @property
193    def is_warn(self) -> bool:
194        return self == OnDestructiveChange.WARN
195
196    @property
197    def is_allow(self) -> bool:
198        return self == OnDestructiveChange.ALLOW

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'>
is_error: bool
188    @property
189    def is_error(self) -> bool:
190        return self == OnDestructiveChange.ERROR
is_warn: bool
192    @property
193    def is_warn(self) -> bool:
194        return self == OnDestructiveChange.WARN
is_allow: bool
196    @property
197    def is_allow(self) -> bool:
198        return self == OnDestructiveChange.ALLOW
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_destructive_change_validator( cls: Type, v: Union[OnDestructiveChange, str, sqlglot.expressions.Identifier]) -> Any:
201def _on_destructive_change_validator(
202    cls: t.Type, v: t.Union[OnDestructiveChange, str, exp.Identifier]
203) -> t.Any:
204    if v and not isinstance(v, OnDestructiveChange):
205        return OnDestructiveChange(
206            v.this.upper() if isinstance(v, (exp.Identifier, exp.Literal)) else v.upper()
207        )
208    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):
238class TimeColumn(PydanticModel):
239    column: exp.Expression
240    format: t.Optional[str] = None
241
242    @classmethod
243    def validator(cls) -> classmethod:
244        def _time_column_validator(v: t.Any, info: ValidationInfo) -> TimeColumn:
245            return TimeColumn.create(v, get_dialect(info.data))
246
247        return field_validator("time_column", mode="before")(_time_column_validator)
248
249    @field_validator("column", mode="before")
250    @classmethod
251    def _column_validator(cls, v: t.Union[str, exp.Expression]) -> exp.Expression:
252        if not v:
253            raise ConfigError("Time Column cannot be empty.")
254        if isinstance(v, str):
255            return exp.to_column(v)
256        return v
257
258    @property
259    def expression(self) -> exp.Expression:
260        """Convert this pydantic model into a time_column SQLGlot expression."""
261        if not self.format:
262            return self.column
263
264        return exp.Tuple(expressions=[self.column, exp.Literal.string(self.format)])
265
266    def to_expression(self, dialect: str) -> exp.Expression:
267        """Convert this pydantic model into a time_column SQLGlot expression."""
268        if not self.format:
269            return self.column
270
271        return exp.Tuple(
272            expressions=[
273                self.column,
274                exp.Literal.string(
275                    format_time(self.format, d.Dialect.get_or_raise(dialect).INVERSE_TIME_MAPPING)
276                ),
277            ]
278        )
279
280    def to_property(self, dialect: str = "") -> exp.Property:
281        return exp.Property(this="time_column", value=self.to_expression(dialect))
282
283    @classmethod
284    def create(cls, v: t.Any, dialect: str) -> Self:
285        if isinstance(v, exp.Tuple):
286            column_expr = v.expressions[0]
287            column = (
288                exp.column(column_expr) if isinstance(column_expr, exp.Identifier) else column_expr
289            )
290            format = v.expressions[1].name if len(v.expressions) > 1 else None
291        elif isinstance(v, exp.Expression):
292            column = exp.column(v) if isinstance(v, exp.Identifier) else v
293            format = None
294        elif isinstance(v, str):
295            column = d.parse_one(v, dialect=dialect)
296            column.meta.pop("sql")
297            format = None
298        elif isinstance(v, dict):
299            column_raw = v["column"]
300            column = (
301                d.parse_one(column_raw, dialect=dialect)
302                if isinstance(column_raw, str)
303                else column_raw
304            )
305            format = v.get("format")
306        elif isinstance(v, TimeColumn):
307            column = v.column
308            format = v.format
309        else:
310            raise ConfigError(f"Invalid time_column: '{v}'.")
311
312        column = quote_identifiers(normalize_identifiers(column, dialect=dialect), dialect=dialect)
313        column.meta["dialect"] = dialect
314
315        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__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __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.Expression
format: Optional[str]
@classmethod
def validator(cls) -> classmethod:
242    @classmethod
243    def validator(cls) -> classmethod:
244        def _time_column_validator(v: t.Any, info: ValidationInfo) -> TimeColumn:
245            return TimeColumn.create(v, get_dialect(info.data))
246
247        return field_validator("time_column", mode="before")(_time_column_validator)
expression: sqlglot.expressions.Expression
258    @property
259    def expression(self) -> exp.Expression:
260        """Convert this pydantic model into a time_column SQLGlot expression."""
261        if not self.format:
262            return self.column
263
264        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.Expression:
266    def to_expression(self, dialect: str) -> exp.Expression:
267        """Convert this pydantic model into a time_column SQLGlot expression."""
268        if not self.format:
269            return self.column
270
271        return exp.Tuple(
272            expressions=[
273                self.column,
274                exp.Literal.string(
275                    format_time(self.format, d.Dialect.get_or_raise(dialect).INVERSE_TIME_MAPPING)
276                ),
277            ]
278        )

Convert this pydantic model into a time_column SQLGlot expression.

def to_property(self, dialect: str = '') -> sqlglot.expressions.Property:
280    def to_property(self, dialect: str = "") -> exp.Property:
281        return exp.Property(this="time_column", value=self.to_expression(dialect))
@classmethod
def create(cls, v: Any, dialect: str) -> typing_extensions.Self:
283    @classmethod
284    def create(cls, v: t.Any, dialect: str) -> Self:
285        if isinstance(v, exp.Tuple):
286            column_expr = v.expressions[0]
287            column = (
288                exp.column(column_expr) if isinstance(column_expr, exp.Identifier) else column_expr
289            )
290            format = v.expressions[1].name if len(v.expressions) > 1 else None
291        elif isinstance(v, exp.Expression):
292            column = exp.column(v) if isinstance(v, exp.Identifier) else v
293            format = None
294        elif isinstance(v, str):
295            column = d.parse_one(v, dialect=dialect)
296            column.meta.pop("sql")
297            format = None
298        elif isinstance(v, dict):
299            column_raw = v["column"]
300            column = (
301                d.parse_one(column_raw, dialect=dialect)
302                if isinstance(column_raw, str)
303                else column_raw
304            )
305            format = v.get("format")
306        elif isinstance(v, TimeColumn):
307            column = v.column
308            format = v.format
309        else:
310            raise ConfigError(f"Invalid time_column: '{v}'.")
311
312        column = quote_identifiers(normalize_identifiers(column, dialect=dialect), dialect=dialect)
313        column.meta["dialect"] = dialect
314
315        return cls(column=column, format=format)
model_config = {'json_encoders': {<class 'sqlglot.expressions.Expression'>: <function _expression_encoder>, <class 'sqlglot.expressions.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.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:
318def _kind_dialect_validator(cls: t.Type, v: t.Optional[str]) -> str:
319    if v is None:
320        return get_dialect({})
321    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):
403class IncrementalByTimeRangeKind(_IncrementalBy):
404    name: t.Literal[ModelKindName.INCREMENTAL_BY_TIME_RANGE] = (
405        ModelKindName.INCREMENTAL_BY_TIME_RANGE
406    )
407    time_column: TimeColumn
408    auto_restatement_intervals: t.Optional[SQLGlotPositiveInt] = None
409    partition_by_time_column: SQLGlotBool = True
410
411    _time_column_validator = TimeColumn.validator()
412
413    def to_expression(
414        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
415    ) -> d.ModelKind:
416        return super().to_expression(
417            expressions=[
418                *(expressions or []),
419                self.time_column.to_property(kwargs.get("dialect") or ""),
420                *_properties(
421                    {
422                        "partition_by_time_column": self.partition_by_time_column,
423                    }
424                ),
425                *(
426                    [_property("auto_restatement_intervals", self.auto_restatement_intervals)]
427                    if self.auto_restatement_intervals is not None
428                    else []
429                ),
430            ]
431        )
432
433    @property
434    def data_hash_values(self) -> t.List[t.Optional[str]]:
435        return [*super().data_hash_values, gen(self.time_column.column), self.time_column.format]
436
437    @property
438    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
439        return [
440            *super().metadata_hash_values,
441            str(self.partition_by_time_column),
442            str(self.auto_restatement_intervals)
443            if self.auto_restatement_intervals is not None
444            else None,
445        ]

!!! 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__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __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 0x792eec027be0>, json_schema_input_type=PydanticUndefined)]]
partition_by_time_column: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x792eec027b50>, json_schema_input_type=PydanticUndefined)]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.Expression]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
413    def to_expression(
414        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
415    ) -> d.ModelKind:
416        return super().to_expression(
417            expressions=[
418                *(expressions or []),
419                self.time_column.to_property(kwargs.get("dialect") or ""),
420                *_properties(
421                    {
422                        "partition_by_time_column": self.partition_by_time_column,
423                    }
424                ),
425                *(
426                    [_property("auto_restatement_intervals", self.auto_restatement_intervals)]
427                    if self.auto_restatement_intervals is not None
428                    else []
429                ),
430            ]
431        )
data_hash_values: List[Optional[str]]
433    @property
434    def data_hash_values(self) -> t.List[t.Optional[str]]:
435        return [*super().data_hash_values, gen(self.time_column.column), self.time_column.format]
metadata_hash_values: List[Optional[str]]
437    @property
438    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
439        return [
440            *super().metadata_hash_values,
441            str(self.partition_by_time_column),
442            str(self.auto_restatement_intervals)
443            if self.auto_restatement_intervals is not None
444            else None,
445        ]
model_config = {'json_encoders': {<class 'sqlglot.expressions.Expression'>: <function _expression_encoder>, <class 'sqlglot.expressions.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.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):
448class IncrementalByUniqueKeyKind(_IncrementalBy):
449    name: t.Literal[ModelKindName.INCREMENTAL_BY_UNIQUE_KEY] = (
450        ModelKindName.INCREMENTAL_BY_UNIQUE_KEY
451    )
452    unique_key: SQLGlotListOfFields
453    when_matched: t.Optional[exp.Whens] = None
454    merge_filter: t.Optional[exp.Expression] = None
455    batch_concurrency: t.Literal[1] = 1
456
457    @field_validator("when_matched", mode="before")
458    def _when_matched_validator(
459        cls,
460        v: t.Optional[t.Union[str, list, exp.Whens]],
461        info: ValidationInfo,
462    ) -> t.Optional[exp.Whens]:
463        if v is None:
464            return v
465        if isinstance(v, list):
466            v = " ".join(v)
467        if isinstance(v, str):
468            # Whens wrap the WHEN clauses, but the parentheses aren't parsed by sqlglot
469            v = v.strip()
470            if v.startswith("("):
471                v = v[1:-1]
472
473            return t.cast(exp.Whens, d.parse_one(v, into=exp.Whens, dialect=get_dialect(info.data)))
474
475        return t.cast(exp.Whens, v.transform(d.replace_merge_table_aliases))
476
477    @field_validator("merge_filter", mode="before")
478    def _merge_filter_validator(
479        cls,
480        v: t.Optional[exp.Expression],
481        info: ValidationInfo,
482    ) -> t.Optional[exp.Expression]:
483        if v is None:
484            return v
485        if isinstance(v, str):
486            v = v.strip()
487            return d.parse_one(v, dialect=get_dialect(info.data))
488
489        return v.transform(d.replace_merge_table_aliases)
490
491    @property
492    def data_hash_values(self) -> t.List[t.Optional[str]]:
493        return [
494            *super().data_hash_values,
495            *(gen(k) for k in self.unique_key),
496            gen(self.when_matched) if self.when_matched is not None else None,
497            gen(self.merge_filter) if self.merge_filter is not None else None,
498        ]
499
500    def to_expression(
501        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
502    ) -> d.ModelKind:
503        return super().to_expression(
504            expressions=[
505                *(expressions or []),
506                *_properties(
507                    {
508                        "unique_key": exp.Tuple(expressions=self.unique_key),
509                        "when_matched": self.when_matched,
510                        "merge_filter": self.merge_filter,
511                    }
512                ),
513            ],
514        )

!!! 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__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __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.Expression], BeforeValidator(func=<function list_of_fields_validator at 0x792eec027d90>, json_schema_input_type=PydanticUndefined)]
when_matched: Optional[sqlglot.expressions.Whens]
merge_filter: Optional[sqlglot.expressions.Expression]
batch_concurrency: Literal[1]
data_hash_values: List[Optional[str]]
491    @property
492    def data_hash_values(self) -> t.List[t.Optional[str]]:
493        return [
494            *super().data_hash_values,
495            *(gen(k) for k in self.unique_key),
496            gen(self.when_matched) if self.when_matched is not None else None,
497            gen(self.merge_filter) if self.merge_filter is not None else None,
498        ]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.Expression]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
500    def to_expression(
501        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
502    ) -> d.ModelKind:
503        return super().to_expression(
504            expressions=[
505                *(expressions or []),
506                *_properties(
507                    {
508                        "unique_key": exp.Tuple(expressions=self.unique_key),
509                        "when_matched": self.when_matched,
510                        "merge_filter": self.merge_filter,
511                    }
512                ),
513            ],
514        )
model_config = {'json_encoders': {<class 'sqlglot.expressions.Expression'>: <function _expression_encoder>, <class 'sqlglot.expressions.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.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):
517class IncrementalByPartitionKind(_Incremental):
518    name: t.Literal[ModelKindName.INCREMENTAL_BY_PARTITION] = ModelKindName.INCREMENTAL_BY_PARTITION
519    forward_only: t.Literal[True] = True
520    disable_restatement: SQLGlotBool = False
521
522    @field_validator("forward_only", mode="before")
523    def _forward_only_validator(cls, v: t.Union[bool, exp.Expression]) -> t.Literal[True]:
524        if v is not True:
525            raise ConfigError(
526                "Do not specify the `forward_only` configuration key - INCREMENTAL_BY_PARTITION models are always forward_only."
527            )
528        return v
529
530    @property
531    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
532        return [
533            *super().metadata_hash_values,
534            str(self.forward_only),
535            str(self.disable_restatement),
536        ]
537
538    def to_expression(
539        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
540    ) -> d.ModelKind:
541        return super().to_expression(
542            expressions=[
543                *(expressions or []),
544                *_properties(
545                    {
546                        "forward_only": self.forward_only,
547                        "disable_restatement": self.disable_restatement,
548                    }
549                ),
550            ],
551        )

!!! 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__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __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 0x792eec027b50>, json_schema_input_type=PydanticUndefined)]
metadata_hash_values: List[Optional[str]]
530    @property
531    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
532        return [
533            *super().metadata_hash_values,
534            str(self.forward_only),
535            str(self.disable_restatement),
536        ]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.Expression]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
538    def to_expression(
539        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
540    ) -> d.ModelKind:
541        return super().to_expression(
542            expressions=[
543                *(expressions or []),
544                *_properties(
545                    {
546                        "forward_only": self.forward_only,
547                        "disable_restatement": self.disable_restatement,
548                    }
549                ),
550            ],
551        )
model_config = {'json_encoders': {<class 'sqlglot.expressions.Expression'>: <function _expression_encoder>, <class 'sqlglot.expressions.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.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
auto_restatement_cron
_ModelKind
model_kind_name
data_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_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_python_models
class IncrementalUnmanagedKind(_Incremental):
554class IncrementalUnmanagedKind(_Incremental):
555    name: t.Literal[ModelKindName.INCREMENTAL_UNMANAGED] = ModelKindName.INCREMENTAL_UNMANAGED
556    insert_overwrite: SQLGlotBool = False
557    forward_only: SQLGlotBool = True
558    disable_restatement: SQLGlotBool = True
559
560    @property
561    def data_hash_values(self) -> t.List[t.Optional[str]]:
562        return [*super().data_hash_values, str(self.insert_overwrite)]
563
564    @property
565    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
566        return [
567            *super().metadata_hash_values,
568            str(self.forward_only),
569            str(self.disable_restatement),
570        ]
571
572    def to_expression(
573        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
574    ) -> d.ModelKind:
575        return super().to_expression(
576            expressions=[
577                *(expressions or []),
578                *_properties(
579                    {
580                        "insert_overwrite": self.insert_overwrite,
581                        "forward_only": self.forward_only,
582                        "disable_restatement": self.disable_restatement,
583                    }
584                ),
585            ],
586        )

!!! 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__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __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 0x792eec027b50>, json_schema_input_type=PydanticUndefined)]
forward_only: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x792eec027b50>, json_schema_input_type=PydanticUndefined)]
disable_restatement: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x792eec027b50>, json_schema_input_type=PydanticUndefined)]
data_hash_values: List[Optional[str]]
560    @property
561    def data_hash_values(self) -> t.List[t.Optional[str]]:
562        return [*super().data_hash_values, str(self.insert_overwrite)]
metadata_hash_values: List[Optional[str]]
564    @property
565    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
566        return [
567            *super().metadata_hash_values,
568            str(self.forward_only),
569            str(self.disable_restatement),
570        ]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.Expression]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
572    def to_expression(
573        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
574    ) -> d.ModelKind:
575        return super().to_expression(
576            expressions=[
577                *(expressions or []),
578                *_properties(
579                    {
580                        "insert_overwrite": self.insert_overwrite,
581                        "forward_only": self.forward_only,
582                        "disable_restatement": self.disable_restatement,
583                    }
584                ),
585            ],
586        )
model_config = {'json_encoders': {<class 'sqlglot.expressions.Expression'>: <function _expression_encoder>, <class 'sqlglot.expressions.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.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
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_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_python_models
class ViewKind(_ModelKind):
589class ViewKind(_ModelKind):
590    name: t.Literal[ModelKindName.VIEW] = ModelKindName.VIEW
591    materialized: SQLGlotBool = False
592
593    @property
594    def data_hash_values(self) -> t.List[t.Optional[str]]:
595        return [*super().data_hash_values, str(self.materialized)]
596
597    @property
598    def supports_python_models(self) -> bool:
599        return False
600
601    def to_expression(
602        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
603    ) -> d.ModelKind:
604        return super().to_expression(
605            expressions=[
606                *(expressions or []),
607                _property("materialized", self.materialized),
608            ],
609        )

!!! 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__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __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 0x792eec027b50>, json_schema_input_type=PydanticUndefined)]
data_hash_values: List[Optional[str]]
593    @property
594    def data_hash_values(self) -> t.List[t.Optional[str]]:
595        return [*super().data_hash_values, str(self.materialized)]
supports_python_models: bool
597    @property
598    def supports_python_models(self) -> bool:
599        return False
def to_expression( self, expressions: Optional[List[sqlglot.expressions.Expression]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
601    def to_expression(
602        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
603    ) -> d.ModelKind:
604        return super().to_expression(
605            expressions=[
606                *(expressions or []),
607                _property("materialized", self.materialized),
608            ],
609        )
model_config = {'json_encoders': {<class 'sqlglot.expressions.Expression'>: <function _expression_encoder>, <class 'sqlglot.expressions.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.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_symbolic
is_materialized
only_execution_time
full_history_restatement_only
class SeedKind(_ModelKind):
612class SeedKind(_ModelKind):
613    name: t.Literal[ModelKindName.SEED] = ModelKindName.SEED
614    path: SQLGlotString
615    batch_size: SQLGlotPositiveInt = 1000
616    csv_settings: t.Optional[CsvSettings] = None
617
618    @field_validator("csv_settings", mode="before")
619    @classmethod
620    def _parse_csv_settings(cls, v: t.Any) -> t.Optional[CsvSettings]:
621        if v is None or isinstance(v, CsvSettings):
622            return v
623        if isinstance(v, exp.Expression):
624            tuple_exp = parse_properties(cls, v, None)
625            if not tuple_exp:
626                return None
627            return CsvSettings(**{e.left.name: e.right for e in tuple_exp.expressions})
628        if isinstance(v, dict):
629            return CsvSettings(**v)
630        return v
631
632    def to_expression(
633        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
634    ) -> d.ModelKind:
635        """Convert the seed kind into a SQLGlot expression."""
636        return super().to_expression(
637            expressions=[
638                *(expressions or []),
639                *_properties(
640                    {
641                        "path": exp.Literal.string(self.path),
642                        "batch_size": self.batch_size,
643                    }
644                ),
645            ],
646        )
647
648    @property
649    def data_hash_values(self) -> t.List[t.Optional[str]]:
650        csv_setting_values = (self.csv_settings or CsvSettings()).dict().values()
651        return [
652            *super().data_hash_values,
653            *(v if isinstance(v, (str, type(None))) else str(v) for v in csv_setting_values),
654        ]
655
656    @property
657    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
658        return [*super().metadata_hash_values, str(self.batch_size)]
659
660    @property
661    def supports_python_models(self) -> bool:
662        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__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __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 0x792eec027ac0>, json_schema_input_type=PydanticUndefined)]
batch_size: typing.Annotated[int, BeforeValidator(func=<function positive_int_validator at 0x792eec027be0>, json_schema_input_type=PydanticUndefined)]
csv_settings: Optional[sqlmesh.core.model.seed.CsvSettings]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.Expression]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
632    def to_expression(
633        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
634    ) -> d.ModelKind:
635        """Convert the seed kind into a SQLGlot expression."""
636        return super().to_expression(
637            expressions=[
638                *(expressions or []),
639                *_properties(
640                    {
641                        "path": exp.Literal.string(self.path),
642                        "batch_size": self.batch_size,
643                    }
644                ),
645            ],
646        )

Convert the seed kind into a SQLGlot expression.

data_hash_values: List[Optional[str]]
648    @property
649    def data_hash_values(self) -> t.List[t.Optional[str]]:
650        csv_setting_values = (self.csv_settings or CsvSettings()).dict().values()
651        return [
652            *super().data_hash_values,
653            *(v if isinstance(v, (str, type(None))) else str(v) for v in csv_setting_values),
654        ]
metadata_hash_values: List[Optional[str]]
656    @property
657    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
658        return [*super().metadata_hash_values, str(self.batch_size)]
supports_python_models: bool
660    @property
661    def supports_python_models(self) -> bool:
662        return False
model_config = {'json_encoders': {<class 'sqlglot.expressions.Expression'>: <function _expression_encoder>, <class 'sqlglot.expressions.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.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_symbolic
is_materialized
only_execution_time
full_history_restatement_only
class FullKind(_ModelKind):
665class FullKind(_ModelKind):
666    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__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __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.Expression'>: <function _expression_encoder>, <class 'sqlglot.expressions.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.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_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_python_models
class SCDType2ByTimeKind(_SCDType2Kind):
746class SCDType2ByTimeKind(_SCDType2Kind):
747    name: t.Literal[ModelKindName.SCD_TYPE_2, ModelKindName.SCD_TYPE_2_BY_TIME] = (
748        ModelKindName.SCD_TYPE_2_BY_TIME
749    )
750    updated_at_name: SQLGlotColumn = Field(exp.column("updated_at"), validate_default=True)
751    updated_at_as_valid_from: SQLGlotBool = False
752
753    _always_validate_updated_at = field_validator("updated_at_name", mode="before")(
754        column_validator
755    )
756
757    @property
758    def data_hash_values(self) -> t.List[t.Optional[str]]:
759        return [
760            *super().data_hash_values,
761            gen(self.updated_at_name),
762            str(self.updated_at_as_valid_from),
763        ]
764
765    def to_expression(
766        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
767    ) -> d.ModelKind:
768        return super().to_expression(
769            expressions=[
770                *(expressions or []),
771                *_properties(
772                    {
773                        "updated_at_name": self.updated_at_name,
774                        "updated_at_as_valid_from": self.updated_at_as_valid_from,
775                    }
776                ),
777            ],
778        )

!!! 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__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __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.Expression, BeforeValidator(func=<function column_validator at 0x792eec027e20>, json_schema_input_type=PydanticUndefined)]
updated_at_as_valid_from: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x792eec027b50>, json_schema_input_type=PydanticUndefined)]
data_hash_values: List[Optional[str]]
757    @property
758    def data_hash_values(self) -> t.List[t.Optional[str]]:
759        return [
760            *super().data_hash_values,
761            gen(self.updated_at_name),
762            str(self.updated_at_as_valid_from),
763        ]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.Expression]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
765    def to_expression(
766        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
767    ) -> d.ModelKind:
768        return super().to_expression(
769            expressions=[
770                *(expressions or []),
771                *_properties(
772                    {
773                        "updated_at_name": self.updated_at_name,
774                        "updated_at_as_valid_from": self.updated_at_as_valid_from,
775                    }
776                ),
777            ],
778        )
model_config = {'json_encoders': {<class 'sqlglot.expressions.Expression'>: <function _expression_encoder>, <class 'sqlglot.expressions.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.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):
781class SCDType2ByColumnKind(_SCDType2Kind):
782    name: t.Literal[ModelKindName.SCD_TYPE_2_BY_COLUMN] = ModelKindName.SCD_TYPE_2_BY_COLUMN
783    columns: SQLGlotListOfColumnsOrStar
784    execution_time_as_valid_from: SQLGlotBool = False
785
786    @property
787    def data_hash_values(self) -> t.List[t.Optional[str]]:
788        columns_sql = (
789            [gen(c) for c in self.columns]
790            if isinstance(self.columns, list)
791            else [gen(self.columns)]
792        )
793        return [*super().data_hash_values, *columns_sql, str(self.execution_time_as_valid_from)]
794
795    def to_expression(
796        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
797    ) -> d.ModelKind:
798        return super().to_expression(
799            expressions=[
800                *(expressions or []),
801                *_properties(
802                    {
803                        "columns": exp.Tuple(expressions=self.columns)
804                        if isinstance(self.columns, list)
805                        else self.columns,
806                        "execution_time_as_valid_from": self.execution_time_as_valid_from,
807                    }
808                ),
809            ],
810        )

!!! 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__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __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[List[sqlglot.expressions.Column], sqlglot.expressions.Star], BeforeValidator(func=<function list_of_columns_or_star_validator at 0x792eec027eb0>, json_schema_input_type=PydanticUndefined)]
execution_time_as_valid_from: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x792eec027b50>, json_schema_input_type=PydanticUndefined)]
data_hash_values: List[Optional[str]]
786    @property
787    def data_hash_values(self) -> t.List[t.Optional[str]]:
788        columns_sql = (
789            [gen(c) for c in self.columns]
790            if isinstance(self.columns, list)
791            else [gen(self.columns)]
792        )
793        return [*super().data_hash_values, *columns_sql, str(self.execution_time_as_valid_from)]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.Expression]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
795    def to_expression(
796        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
797    ) -> d.ModelKind:
798        return super().to_expression(
799            expressions=[
800                *(expressions or []),
801                *_properties(
802                    {
803                        "columns": exp.Tuple(expressions=self.columns)
804                        if isinstance(self.columns, list)
805                        else self.columns,
806                        "execution_time_as_valid_from": self.execution_time_as_valid_from,
807                    }
808                ),
809            ],
810        )
model_config = {'json_encoders': {<class 'sqlglot.expressions.Expression'>: <function _expression_encoder>, <class 'sqlglot.expressions.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.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):
813class ManagedKind(_ModelKind):
814    name: t.Literal[ModelKindName.MANAGED] = ModelKindName.MANAGED
815    disable_restatement: t.Literal[True] = True
816
817    @property
818    def supports_python_models(self) -> bool:
819        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__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __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
817    @property
818    def supports_python_models(self) -> bool:
819        return False
model_config = {'json_encoders': {<class 'sqlglot.expressions.Expression'>: <function _expression_encoder>, <class 'sqlglot.expressions.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.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_symbolic
is_materialized
only_execution_time
full_history_restatement_only
class EmbeddedKind(_ModelKind):
822class EmbeddedKind(_ModelKind):
823    name: t.Literal[ModelKindName.EMBEDDED] = ModelKindName.EMBEDDED
824
825    @property
826    def supports_python_models(self) -> bool:
827        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__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __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
825    @property
826    def supports_python_models(self) -> bool:
827        return False
model_config = {'json_encoders': {<class 'sqlglot.expressions.Expression'>: <function _expression_encoder>, <class 'sqlglot.expressions.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.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_symbolic
is_materialized
only_execution_time
full_history_restatement_only
class ExternalKind(_ModelKind):
830class ExternalKind(_ModelKind):
831    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__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __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.Expression'>: <function _expression_encoder>, <class 'sqlglot.expressions.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.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_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_python_models
class CustomKind(_ModelKind):
834class CustomKind(_ModelKind):
835    name: t.Literal[ModelKindName.CUSTOM] = ModelKindName.CUSTOM
836    materialization: str
837    materialization_properties_: t.Optional[exp.Tuple] = Field(
838        default=None, alias="materialization_properties"
839    )
840    forward_only: SQLGlotBool = False
841    disable_restatement: SQLGlotBool = False
842    batch_size: t.Optional[SQLGlotPositiveInt] = None
843    batch_concurrency: t.Optional[SQLGlotPositiveInt] = None
844    lookback: t.Optional[SQLGlotPositiveInt] = None
845    auto_restatement_cron: t.Optional[SQLGlotCron] = None
846    auto_restatement_intervals: t.Optional[SQLGlotPositiveInt] = None
847
848    # so that CustomKind subclasses know the dialect when validating / normalizing / interpreting values in `materialization_properties`
849    dialect: str = Field(exclude=True)
850
851    _properties_validator = properties_validator
852
853    @field_validator("materialization", mode="before")
854    @classmethod
855    def _validate_materialization(cls, v: t.Any) -> str:
856        # note: create_model_kind() validates the custom materialization class
857        return validate_string(v)
858
859    @property
860    def materialization_properties(self) -> CustomMaterializationProperties:
861        """A dictionary of materialization properties."""
862        if not self.materialization_properties_:
863            return {}
864        return d.interpret_key_value_pairs(self.materialization_properties_)
865
866    @property
867    def data_hash_values(self) -> t.List[t.Optional[str]]:
868        return [
869            *super().data_hash_values,
870            self.materialization,
871            gen(self.materialization_properties_) if self.materialization_properties_ else None,
872            str(self.lookback) if self.lookback is not None else None,
873        ]
874
875    @property
876    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
877        return [
878            *super().metadata_hash_values,
879            str(self.batch_size) if self.batch_size is not None else None,
880            str(self.batch_concurrency) if self.batch_concurrency is not None else None,
881            str(self.forward_only),
882            str(self.disable_restatement),
883            self.auto_restatement_cron,
884            str(self.auto_restatement_intervals)
885            if self.auto_restatement_intervals is not None
886            else None,
887        ]
888
889    def to_expression(
890        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
891    ) -> d.ModelKind:
892        return super().to_expression(
893            expressions=[
894                *(expressions or []),
895                *_properties(
896                    {
897                        "materialization": exp.Literal.string(self.materialization),
898                        "materialization_properties": self.materialization_properties_,
899                        "forward_only": self.forward_only,
900                        "disable_restatement": self.disable_restatement,
901                        "batch_size": self.batch_size,
902                        "batch_concurrency": self.batch_concurrency,
903                        "lookback": self.lookback,
904                        "auto_restatement_cron": self.auto_restatement_cron,
905                        "auto_restatement_intervals": self.auto_restatement_intervals,
906                    }
907                ),
908            ],
909        )

!!! 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__: Metadata for generic models; contains data used for a similar purpose to __args__, __origin__, __parameters__ in typing-module generics. May eventually be replaced by these.
  • __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.Tuple]
forward_only: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x792eec027b50>, json_schema_input_type=PydanticUndefined)]
disable_restatement: typing.Annotated[bool, BeforeValidator(func=<function bool_validator at 0x792eec027b50>, json_schema_input_type=PydanticUndefined)]
batch_size: Optional[Annotated[int, BeforeValidator(func=<function positive_int_validator at 0x792eec027be0>, json_schema_input_type=PydanticUndefined)]]
batch_concurrency: Optional[Annotated[int, BeforeValidator(func=<function positive_int_validator at 0x792eec027be0>, json_schema_input_type=PydanticUndefined)]]
lookback: Optional[Annotated[int, BeforeValidator(func=<function positive_int_validator at 0x792eec027be0>, json_schema_input_type=PydanticUndefined)]]
auto_restatement_cron: Optional[Annotated[str, BeforeValidator(func=<function cron_validator at 0x792eec027f40>, json_schema_input_type=PydanticUndefined)]]
auto_restatement_intervals: Optional[Annotated[int, BeforeValidator(func=<function positive_int_validator at 0x792eec027be0>, json_schema_input_type=PydanticUndefined)]]
dialect: str
materialization_properties: Dict[str, sqlglot.expressions.Expression | str | int | float | bool]
859    @property
860    def materialization_properties(self) -> CustomMaterializationProperties:
861        """A dictionary of materialization properties."""
862        if not self.materialization_properties_:
863            return {}
864        return d.interpret_key_value_pairs(self.materialization_properties_)

A dictionary of materialization properties.

data_hash_values: List[Optional[str]]
866    @property
867    def data_hash_values(self) -> t.List[t.Optional[str]]:
868        return [
869            *super().data_hash_values,
870            self.materialization,
871            gen(self.materialization_properties_) if self.materialization_properties_ else None,
872            str(self.lookback) if self.lookback is not None else None,
873        ]
metadata_hash_values: List[Optional[str]]
875    @property
876    def metadata_hash_values(self) -> t.List[t.Optional[str]]:
877        return [
878            *super().metadata_hash_values,
879            str(self.batch_size) if self.batch_size is not None else None,
880            str(self.batch_concurrency) if self.batch_concurrency is not None else None,
881            str(self.forward_only),
882            str(self.disable_restatement),
883            self.auto_restatement_cron,
884            str(self.auto_restatement_intervals)
885            if self.auto_restatement_intervals is not None
886            else None,
887        ]
def to_expression( self, expressions: Optional[List[sqlglot.expressions.Expression]] = None, **kwargs: Any) -> sqlmesh.core.dialect.ModelKind:
889    def to_expression(
890        self, expressions: t.Optional[t.List[exp.Expression]] = None, **kwargs: t.Any
891    ) -> d.ModelKind:
892        return super().to_expression(
893            expressions=[
894                *(expressions or []),
895                *_properties(
896                    {
897                        "materialization": exp.Literal.string(self.materialization),
898                        "materialization_properties": self.materialization_properties_,
899                        "forward_only": self.forward_only,
900                        "disable_restatement": self.disable_restatement,
901                        "batch_size": self.batch_size,
902                        "batch_concurrency": self.batch_concurrency,
903                        "lookback": self.lookback,
904                        "auto_restatement_cron": self.auto_restatement_cron,
905                        "auto_restatement_intervals": self.auto_restatement_intervals,
906                    }
907                ),
908            ],
909        )
model_config = {'json_encoders': {<class 'sqlglot.expressions.Expression'>: <function _expression_encoder>, <class 'sqlglot.expressions.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.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_symbolic
is_materialized
only_execution_time
full_history_restatement_only
supports_python_models
MODEL_KIND_NAME_TO_TYPE: Dict[str, Type[Annotated[Union[EmbeddedKind, ExternalKind, FullKind, IncrementalByTimeRangeKind, IncrementalByUniqueKeyKind, IncrementalByPartitionKind, IncrementalUnmanagedKind, SeedKind, ViewKind, SCDType2ByTimeKind, SCDType2ByColumnKind, CustomKind, ManagedKind], 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'>}
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], FieldInfo(annotation=NoneType, required=True, discriminator='name')]]:
949def model_kind_type_from_name(name: t.Optional[str]) -> t.Type[ModelKind]:
950    klass = MODEL_KIND_NAME_TO_TYPE.get(name) if name else None
951    if not klass:
952        raise ConfigError(f"Invalid model kind '{name}'")
953    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], FieldInfo(annotation=NoneType, required=True, discriminator='name')]:
 956def create_model_kind(v: t.Any, dialect: str, defaults: t.Dict[str, t.Any]) -> ModelKind:
 957    if isinstance(v, _ModelKind):
 958        return t.cast(ModelKind, v)
 959
 960    if isinstance(v, (d.ModelKind, dict)):
 961        props = (
 962            {prop.name: prop.args.get("value") for prop in v.expressions}
 963            if isinstance(v, d.ModelKind)
 964            else v
 965        )
 966        name = v.this if isinstance(v, d.ModelKind) else props.get("name")
 967
 968        # We want to ensure whatever name is provided to construct the class is the same name that will be
 969        # found inside the class itself in order to avoid a change during plan/apply for legacy aliases.
 970        # Ex: Pass in `SCD_TYPE_2` then we want to ensure we get `SCD_TYPE_2` as the kind name
 971        # instead of `SCD_TYPE_2_BY_TIME`.
 972        props["name"] = name
 973        kind_type = model_kind_type_from_name(name)
 974
 975        if "dialect" in kind_type.all_fields() and props.get("dialect") is None:
 976            props["dialect"] = dialect
 977
 978        # only pass the on_destructive_change user default to models inheriting from _Incremental
 979        # that don't explicitly set it in the model definition
 980        if (
 981            issubclass(kind_type, _Incremental)
 982            and props.get("on_destructive_change") is None
 983            and defaults.get("on_destructive_change") is not None
 984        ):
 985            props["on_destructive_change"] = defaults.get("on_destructive_change")
 986
 987        if kind_type == CustomKind:
 988            # load the custom materialization class and check if it uses a custom kind type
 989            from sqlmesh.core.snapshot.evaluator import get_custom_materialization_type
 990
 991            if "materialization" not in props:
 992                raise ConfigError(
 993                    "The 'materialization' property is required for models of the CUSTOM kind"
 994                )
 995
 996            # The below call will print a warning if a materialization with the given name doesn't exist
 997            # we dont want to throw an error here because we still want Models with a CustomKind to be able
 998            # to be serialized / deserialized in contexts where the custom materialization class may not be available,
 999            # such as in HTTP request handlers
1000            custom_materialization = get_custom_materialization_type(
1001                validate_string(props.get("materialization")), raise_errors=False
1002            )
1003            if custom_materialization is not None:
1004                actual_kind_type, _ = custom_materialization
1005                return actual_kind_type(**props)
1006
1007        return kind_type(**props)
1008
1009    name = (v.name if isinstance(v, exp.Expression) else str(v)).upper()
1010    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], FieldInfo(annotation=NoneType, required=True, discriminator='name')]:
1013def _model_kind_validator(cls: t.Type, v: t.Any, info: t.Optional[ValidationInfo]) -> ModelKind:
1014    dialect = get_dialect(info.data) if info else ""
1015    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.