Edit on GitHub

sqlmesh.utils.pydantic

  1from __future__ import annotations
  2
  3import json
  4import typing as t
  5from datetime import tzinfo
  6
  7import pydantic
  8from pydantic import ValidationInfo as ValidationInfo
  9from pydantic.fields import FieldInfo
 10from sqlglot import exp, parse_one
 11from sqlglot.helper import ensure_list
 12from sqlglot.optimizer.normalize_identifiers import normalize_identifiers
 13from sqlglot.optimizer.qualify_columns import quote_identifiers
 14
 15from sqlmesh.core import dialect as d
 16from sqlmesh.utils import str_to_bool
 17
 18if t.TYPE_CHECKING:
 19    from sqlglot._typing import E
 20
 21    Model = t.TypeVar("Model", bound="PydanticModel")
 22
 23
 24T = t.TypeVar("T")
 25DEFAULT_ARGS = {"exclude_none": True, "by_alias": True}
 26PRIVATE_FIELDS = "__pydantic_private__"
 27PYDANTIC_MAJOR_VERSION, PYDANTIC_MINOR_VERSION = [int(p) for p in pydantic.__version__.split(".")][
 28    :2
 29]
 30
 31
 32def field_validator(*args: t.Any, **kwargs: t.Any) -> t.Callable[[t.Any], t.Any]:
 33    return pydantic.field_validator(*args, **kwargs)
 34
 35
 36def model_validator(*args: t.Any, **kwargs: t.Any) -> t.Callable[[t.Any], t.Any]:
 37    return pydantic.model_validator(*args, **kwargs)
 38
 39
 40def field_serializer(*args: t.Any, **kwargs: t.Any) -> t.Callable[[t.Any], t.Any]:
 41    return pydantic.field_serializer(*args, **kwargs)
 42
 43
 44def validation_data(info_or_data: t.Any) -> t.Dict[str, t.Any]:
 45    """Safely extract the validated-data dict from a ValidationInfo, dict, or None.
 46
 47    Pydantic 2.13+ sets ValidationInfo.data to None during model_validate_json().
 48    This normalizes all inputs to a dict, returning an empty dict when data is unavailable.
 49    """
 50    if isinstance(info_or_data, dict):
 51        return info_or_data
 52    if info_or_data is not None:
 53        return info_or_data.data or {}
 54    return {}
 55
 56
 57def get_dialect(values: t.Any) -> str:
 58    """Extracts dialect from a dict or pydantic obj, defaulting to the globally set dialect.
 59
 60    Python models allow users to instantiate pydantic models by hand. This is problematic
 61    because the validators kick in with the SQLGLot dialect. To instantiate Pydantic Models used
 62    in python models using the project default dialect, we set a class variable on the model
 63    registry and use that here.
 64    """
 65
 66    from sqlmesh.core.model import model
 67
 68    dialect = validation_data(values).get("dialect")
 69    return model._dialect if dialect is None else dialect  # type: ignore
 70
 71
 72def _expression_encoder(e: exp.Expr) -> str:
 73    return e.meta.get("sql") or e.sql(dialect=e.meta.get("dialect"))
 74
 75
 76AuditQueryTypes = t.Union[exp.Query, d.JinjaQuery]
 77ModelQueryTypes = t.Union[exp.Query, d.JinjaQuery, d.MacroFunc]
 78
 79
 80class PydanticModel(pydantic.BaseModel):
 81    model_config = pydantic.ConfigDict(
 82        # Even though Pydantic v2 kept support for json_encoders, the functionality has been
 83        # crippled badly. Here we need to enumerate all different ways of how sqlglot expressions
 84        # show up in pydantic models.
 85        json_encoders={
 86            exp.Expr: _expression_encoder,
 87            exp.DataType: _expression_encoder,
 88            exp.Tuple: _expression_encoder,
 89            AuditQueryTypes: _expression_encoder,  # type: ignore
 90            ModelQueryTypes: _expression_encoder,  # type: ignore
 91            tzinfo: lambda tz: tz.key,
 92        },
 93        arbitrary_types_allowed=True,
 94        extra="forbid",
 95        protected_namespaces=(),
 96    )
 97
 98    _hash_func_mapping: t.ClassVar[t.Dict[t.Type[t.Any], t.Callable[[t.Any], int]]] = {}
 99
100    def dict(self, **kwargs: t.Any) -> t.Dict[str, t.Any]:
101        kwargs = {**DEFAULT_ARGS, **kwargs}
102        return super().model_dump(**kwargs)  # type: ignore
103
104    def json(
105        self,
106        **kwargs: t.Any,
107    ) -> str:
108        kwargs = {**DEFAULT_ARGS, **kwargs}
109        # Pydantic v2 doesn't support arbitrary arguments for json.dump().
110        if kwargs.pop("sort_keys", False):
111            return json.dumps(super().model_dump(mode="json", **kwargs), sort_keys=True)
112
113        return super().model_dump_json(**kwargs)
114
115    def copy(self: "Model", **kwargs: t.Any) -> "Model":
116        return super().model_copy(**kwargs)
117
118    @property
119    def fields_set(self: "Model") -> t.Set[str]:
120        return self.__pydantic_fields_set__
121
122    @classmethod
123    def parse_obj(cls: t.Type["Model"], obj: t.Any) -> "Model":
124        return super().model_validate(obj)
125
126    @classmethod
127    def parse_raw(cls: t.Type["Model"], b: t.Union[str, bytes], **kwargs: t.Any) -> "Model":
128        return super().model_validate_json(b, **kwargs)
129
130    @classmethod
131    def missing_required_fields(
132        cls: t.Type["PydanticModel"], provided_fields: t.Set[str]
133    ) -> t.Set[str]:
134        return cls.required_fields() - provided_fields
135
136    @classmethod
137    def extra_fields(cls: t.Type["PydanticModel"], provided_fields: t.Set[str]) -> t.Set[str]:
138        return provided_fields - cls.all_fields()
139
140    @classmethod
141    def all_fields(cls: t.Type["PydanticModel"]) -> t.Set[str]:
142        return cls._fields()
143
144    @classmethod
145    def all_field_infos(cls: t.Type["PydanticModel"]) -> t.Dict[str, FieldInfo]:
146        return cls.model_fields
147
148    @classmethod
149    def required_fields(cls: t.Type["PydanticModel"]) -> t.Set[str]:
150        return cls._fields(lambda field: field.is_required())
151
152    @classmethod
153    def _fields(
154        cls: t.Type["PydanticModel"],
155        predicate: t.Callable[[t.Any], bool] = lambda _: True,
156    ) -> t.Set[str]:
157        return {
158            field_info.alias if field_info.alias else field_name
159            for field_name, field_info in cls.all_field_infos().items()
160            if predicate(field_info)
161        }
162
163    def __eq__(self, other: t.Any) -> bool:
164        if (PYDANTIC_MAJOR_VERSION, PYDANTIC_MINOR_VERSION) < (2, 6):
165            if isinstance(other, pydantic.BaseModel):
166                return self.dict() == other.dict()
167            return self.dict() == other
168        return super().__eq__(other)
169
170    def __hash__(self) -> int:
171        if (PYDANTIC_MAJOR_VERSION, PYDANTIC_MINOR_VERSION) < (2, 6):
172            obj = {k: v for k, v in self.__dict__.items() if k in self.all_field_infos()}
173            return hash(self.__class__) + hash(tuple(obj.values()))
174
175        from pydantic._internal._model_construction import make_hash_func  # type: ignore
176
177        if self.__class__ not in PydanticModel._hash_func_mapping:
178            PydanticModel._hash_func_mapping[self.__class__] = make_hash_func(self.__class__)
179
180        return PydanticModel._hash_func_mapping[self.__class__](self)
181
182    def __str__(self) -> str:
183        args = []
184
185        for k, info in self.all_field_infos().items():
186            v = getattr(self, k)
187
188            if type(v) != type(info.default) or v != info.default:
189                args.append(f"{k}: {v}")
190
191        return f"{self.__class__.__name__}<{', '.join(args)}>"
192
193    def __repr__(self) -> str:
194        return str(self)
195
196
197def validate_list_of_strings(v: t.Any) -> t.List[str]:
198    if isinstance(v, exp.Identifier):
199        return [v.name]
200    if isinstance(v, (exp.Tuple, exp.Array)):
201        return [e.name for e in v.expressions]
202    return [i.name if isinstance(i, exp.Identifier) else str(i) for i in v]
203
204
205def validate_string(v: t.Any) -> str:
206    if isinstance(v, exp.Expr):
207        return v.name
208    return str(v)
209
210
211def validate_expression(expression: E, dialect: str) -> E:
212    # this normalizes and quotes identifiers in the given expression according the specified dialect
213    # it also sets expression.meta["dialect"] so that when we serialize for state, the expression is serialized in the correct dialect
214    return _get_field(expression, {"dialect": dialect})  # type: ignore
215
216
217def bool_validator(v: t.Any) -> bool:
218    if isinstance(v, exp.Boolean):
219        return v.this
220    if isinstance(v, exp.Expr):
221        return str_to_bool(v.name)
222    return str_to_bool(str(v or ""))
223
224
225def positive_int_validator(v: t.Any) -> int:
226    if isinstance(v, exp.Expr) and v.is_int:
227        v = int(v.name)
228    if not isinstance(v, int):
229        raise ValueError(f"Invalid num {v}. Value must be an integer value")
230    if v <= 0:
231        raise ValueError(f"Invalid num {v}. Value must be a positive integer")
232    return v
233
234
235def validation_error_message(error: pydantic.ValidationError, base: str) -> str:
236    errors = "\n  ".join(_formatted_validation_errors(error))
237    return f"{base}\n  {errors}"
238
239
240def _formatted_validation_errors(error: pydantic.ValidationError) -> t.List[str]:
241    result = []
242    for e in error.errors():
243        msg = e["msg"]
244        loc: t.Optional[t.Tuple] = e.get("loc")
245        loc_str = ".".join(loc) if loc else None
246        result.append(f"Invalid field '{loc_str}':\n    {msg}" if loc_str else msg)
247    return result
248
249
250def _get_field(
251    v: t.Any,
252    values: t.Any,
253) -> exp.Expr:
254    dialect = get_dialect(values)
255
256    if isinstance(v, exp.Expr):
257        expression = v
258    else:
259        expression = parse_one(v, dialect=dialect)
260
261    expression = exp.column(expression) if isinstance(expression, exp.Identifier) else expression
262    expression = quote_identifiers(
263        normalize_identifiers(expression, dialect=dialect), dialect=dialect
264    )
265    expression.meta["dialect"] = dialect
266
267    return expression
268
269
270def _get_fields(
271    v: t.Any,
272    values: t.Any,
273) -> t.List[exp.Expr]:
274    dialect = get_dialect(values)
275
276    if isinstance(v, (exp.Tuple, exp.Array)):
277        expressions: t.List[exp.Expr] = v.expressions
278    elif isinstance(v, exp.Expr):
279        expressions = [v]
280    else:
281        items: t.List[t.Any] = ensure_list(v)
282        expressions = [
283            parse_one(entry, dialect=dialect) if isinstance(entry, str) else entry  # type: ignore[misc]
284            for entry in items
285        ]
286
287    results = []
288
289    for expr in expressions:
290        results.append(_get_field(expr, values))
291
292    return results
293
294
295def list_of_fields_validator(v: t.Any, values: t.Any) -> t.List[exp.Expr]:
296    return _get_fields(v, values)
297
298
299def column_validator(v: t.Any, values: t.Any) -> exp.Column:
300    expression = _get_field(v, values)
301    if not isinstance(expression, exp.Column):
302        raise ValueError(f"Invalid column {expression}. Value must be a column")
303    return expression
304
305
306def list_of_fields_or_star_validator(
307    v: t.Any, values: t.Any
308) -> t.Union[exp.Star, t.List[exp.Expr]]:
309    expressions = _get_fields(v, values)
310    if len(expressions) == 1 and isinstance(expressions[0], exp.Star):
311        return t.cast(exp.Star, expressions[0])
312    return t.cast(t.List[exp.Expr], expressions)
313
314
315def cron_validator(v: t.Any) -> str:
316    if isinstance(v, exp.Expr):
317        v = v.name
318
319    from croniter import CroniterBadCronError, croniter
320
321    if not isinstance(v, str):
322        raise ValueError(f"Invalid cron expression '{v}'. Value must be a string.")
323
324    try:
325        croniter(v)
326    except CroniterBadCronError:
327        raise ValueError(f"Invalid cron expression '{v}'")
328    return v
329
330
331def get_concrete_types_from_typehint(typehint: type[t.Any]) -> set[type[t.Any]]:
332    concrete_types = set()
333    unpacked = t.get_origin(typehint)
334    if unpacked is None:
335        if type(typehint) == type(type):
336            return {typehint}
337    elif unpacked is t.Union:
338        for item in t.get_args(typehint):
339            if str(item).startswith("typing."):
340                concrete_types |= get_concrete_types_from_typehint(item)
341            else:
342                concrete_types.add(item)
343    else:
344        concrete_types.add(unpacked)
345
346    return concrete_types
347
348
349if t.TYPE_CHECKING:
350    SQLGlotListOfStrings = t.List[str]
351    SQLGlotString = str
352    SQLGlotBool = bool
353    SQLGlotPositiveInt = int
354    SQLGlotColumn = exp.Column
355    SQLGlotListOfFields = t.List[exp.Expr]
356    SQLGlotListOfFieldsOrStar = t.Union[SQLGlotListOfFields, exp.Star]
357    SQLGlotCron = str
358else:
359    from pydantic.functional_validators import BeforeValidator
360
361    SQLGlotListOfStrings = t.Annotated[t.List[str], BeforeValidator(validate_list_of_strings)]
362    SQLGlotString = t.Annotated[str, BeforeValidator(validate_string)]
363    SQLGlotBool = t.Annotated[bool, BeforeValidator(bool_validator)]
364    SQLGlotPositiveInt = t.Annotated[int, BeforeValidator(positive_int_validator)]
365    SQLGlotColumn = t.Annotated[exp.Expr, BeforeValidator(column_validator)]
366    SQLGlotListOfFields = t.Annotated[t.List[exp.Expr], BeforeValidator(list_of_fields_validator)]
367    SQLGlotListOfFieldsOrStar = t.Annotated[
368        t.Union[SQLGlotListOfFields, exp.Star], BeforeValidator(list_of_fields_or_star_validator)
369    ]
370    SQLGlotCron = t.Annotated[str, BeforeValidator(cron_validator)]
DEFAULT_ARGS = {'exclude_none': True, 'by_alias': True}
PRIVATE_FIELDS = '__pydantic_private__'
def field_validator(*args: Any, **kwargs: Any) -> Callable[[Any], Any]:
33def field_validator(*args: t.Any, **kwargs: t.Any) -> t.Callable[[t.Any], t.Any]:
34    return pydantic.field_validator(*args, **kwargs)
def model_validator(*args: Any, **kwargs: Any) -> Callable[[Any], Any]:
37def model_validator(*args: t.Any, **kwargs: t.Any) -> t.Callable[[t.Any], t.Any]:
38    return pydantic.model_validator(*args, **kwargs)
def field_serializer(*args: Any, **kwargs: Any) -> Callable[[Any], Any]:
41def field_serializer(*args: t.Any, **kwargs: t.Any) -> t.Callable[[t.Any], t.Any]:
42    return pydantic.field_serializer(*args, **kwargs)
def validation_data(info_or_data: Any) -> Dict[str, Any]:
45def validation_data(info_or_data: t.Any) -> t.Dict[str, t.Any]:
46    """Safely extract the validated-data dict from a ValidationInfo, dict, or None.
47
48    Pydantic 2.13+ sets ValidationInfo.data to None during model_validate_json().
49    This normalizes all inputs to a dict, returning an empty dict when data is unavailable.
50    """
51    if isinstance(info_or_data, dict):
52        return info_or_data
53    if info_or_data is not None:
54        return info_or_data.data or {}
55    return {}

Safely extract the validated-data dict from a ValidationInfo, dict, or None.

Pydantic 2.13+ sets ValidationInfo.data to None during model_validate_json(). This normalizes all inputs to a dict, returning an empty dict when data is unavailable.

def get_dialect(values: Any) -> str:
58def get_dialect(values: t.Any) -> str:
59    """Extracts dialect from a dict or pydantic obj, defaulting to the globally set dialect.
60
61    Python models allow users to instantiate pydantic models by hand. This is problematic
62    because the validators kick in with the SQLGLot dialect. To instantiate Pydantic Models used
63    in python models using the project default dialect, we set a class variable on the model
64    registry and use that here.
65    """
66
67    from sqlmesh.core.model import model
68
69    dialect = validation_data(values).get("dialect")
70    return model._dialect if dialect is None else dialect  # type: ignore

Extracts dialect from a dict or pydantic obj, defaulting to the globally set dialect.

Python models allow users to instantiate pydantic models by hand. This is problematic because the validators kick in with the SQLGLot dialect. To instantiate Pydantic Models used in python models using the project default dialect, we set a class variable on the model registry and use that here.

AuditQueryTypes = typing.Union[sqlglot.expressions.query.Query, sqlmesh.core.dialect.JinjaQuery]
ModelQueryTypes = typing.Union[sqlglot.expressions.query.Query, sqlmesh.core.dialect.JinjaQuery, sqlmesh.core.dialect.MacroFunc]
class PydanticModel(pydantic.main.BaseModel):
 81class PydanticModel(pydantic.BaseModel):
 82    model_config = pydantic.ConfigDict(
 83        # Even though Pydantic v2 kept support for json_encoders, the functionality has been
 84        # crippled badly. Here we need to enumerate all different ways of how sqlglot expressions
 85        # show up in pydantic models.
 86        json_encoders={
 87            exp.Expr: _expression_encoder,
 88            exp.DataType: _expression_encoder,
 89            exp.Tuple: _expression_encoder,
 90            AuditQueryTypes: _expression_encoder,  # type: ignore
 91            ModelQueryTypes: _expression_encoder,  # type: ignore
 92            tzinfo: lambda tz: tz.key,
 93        },
 94        arbitrary_types_allowed=True,
 95        extra="forbid",
 96        protected_namespaces=(),
 97    )
 98
 99    _hash_func_mapping: t.ClassVar[t.Dict[t.Type[t.Any], t.Callable[[t.Any], int]]] = {}
100
101    def dict(self, **kwargs: t.Any) -> t.Dict[str, t.Any]:
102        kwargs = {**DEFAULT_ARGS, **kwargs}
103        return super().model_dump(**kwargs)  # type: ignore
104
105    def json(
106        self,
107        **kwargs: t.Any,
108    ) -> str:
109        kwargs = {**DEFAULT_ARGS, **kwargs}
110        # Pydantic v2 doesn't support arbitrary arguments for json.dump().
111        if kwargs.pop("sort_keys", False):
112            return json.dumps(super().model_dump(mode="json", **kwargs), sort_keys=True)
113
114        return super().model_dump_json(**kwargs)
115
116    def copy(self: "Model", **kwargs: t.Any) -> "Model":
117        return super().model_copy(**kwargs)
118
119    @property
120    def fields_set(self: "Model") -> t.Set[str]:
121        return self.__pydantic_fields_set__
122
123    @classmethod
124    def parse_obj(cls: t.Type["Model"], obj: t.Any) -> "Model":
125        return super().model_validate(obj)
126
127    @classmethod
128    def parse_raw(cls: t.Type["Model"], b: t.Union[str, bytes], **kwargs: t.Any) -> "Model":
129        return super().model_validate_json(b, **kwargs)
130
131    @classmethod
132    def missing_required_fields(
133        cls: t.Type["PydanticModel"], provided_fields: t.Set[str]
134    ) -> t.Set[str]:
135        return cls.required_fields() - provided_fields
136
137    @classmethod
138    def extra_fields(cls: t.Type["PydanticModel"], provided_fields: t.Set[str]) -> t.Set[str]:
139        return provided_fields - cls.all_fields()
140
141    @classmethod
142    def all_fields(cls: t.Type["PydanticModel"]) -> t.Set[str]:
143        return cls._fields()
144
145    @classmethod
146    def all_field_infos(cls: t.Type["PydanticModel"]) -> t.Dict[str, FieldInfo]:
147        return cls.model_fields
148
149    @classmethod
150    def required_fields(cls: t.Type["PydanticModel"]) -> t.Set[str]:
151        return cls._fields(lambda field: field.is_required())
152
153    @classmethod
154    def _fields(
155        cls: t.Type["PydanticModel"],
156        predicate: t.Callable[[t.Any], bool] = lambda _: True,
157    ) -> t.Set[str]:
158        return {
159            field_info.alias if field_info.alias else field_name
160            for field_name, field_info in cls.all_field_infos().items()
161            if predicate(field_info)
162        }
163
164    def __eq__(self, other: t.Any) -> bool:
165        if (PYDANTIC_MAJOR_VERSION, PYDANTIC_MINOR_VERSION) < (2, 6):
166            if isinstance(other, pydantic.BaseModel):
167                return self.dict() == other.dict()
168            return self.dict() == other
169        return super().__eq__(other)
170
171    def __hash__(self) -> int:
172        if (PYDANTIC_MAJOR_VERSION, PYDANTIC_MINOR_VERSION) < (2, 6):
173            obj = {k: v for k, v in self.__dict__.items() if k in self.all_field_infos()}
174            return hash(self.__class__) + hash(tuple(obj.values()))
175
176        from pydantic._internal._model_construction import make_hash_func  # type: ignore
177
178        if self.__class__ not in PydanticModel._hash_func_mapping:
179            PydanticModel._hash_func_mapping[self.__class__] = make_hash_func(self.__class__)
180
181        return PydanticModel._hash_func_mapping[self.__class__](self)
182
183    def __str__(self) -> str:
184        args = []
185
186        for k, info in self.all_field_infos().items():
187            v = getattr(self, k)
188
189            if type(v) != type(info.default) or v != info.default:
190                args.append(f"{k}: {v}")
191
192        return f"{self.__class__.__name__}<{', '.join(args)}>"
193
194    def __repr__(self) -> str:
195        return str(self)

!!! abstract "Usage Documentation" Models

A base class for creating Pydantic models.

Attributes:
  • __class_vars__: The names of the class variables defined on the model.
  • __private_attributes__: Metadata about the private attributes of the model.
  • __signature__: The synthesized __init__ [Signature][inspect.Signature] of the model.
  • __pydantic_complete__: Whether model building is completed, or if there are still undefined fields.
  • __pydantic_core_schema__: The core schema of the model.
  • __pydantic_custom_init__: Whether the model has a custom __init__ function.
  • __pydantic_decorators__: Metadata containing the decorators defined on the model. This replaces Model.__validators__ and Model.__root_validators__ from Pydantic V1.
  • __pydantic_generic_metadata__: A dictionary containing metadata about generic Pydantic models. The origin and args items map to the [__origin__][genericalias.__origin__] and [__args__][genericalias.__args__] attributes of [generic aliases][types-genericalias], and the parameter item maps to the __parameter__ attribute of generic classes.
  • __pydantic_parent_namespace__: Parent namespace of the model, used for automatic rebuilding of models.
  • __pydantic_post_init__: The name of the post-init method for the model, if defined.
  • __pydantic_root_model__: Whether the model is a [RootModel][pydantic.root_model.RootModel].
  • __pydantic_serializer__: The pydantic-core SchemaSerializer used to dump instances of the model.
  • __pydantic_validator__: The pydantic-core SchemaValidator used to validate instances of the model.
  • __pydantic_fields__: A dictionary of field names and their corresponding [FieldInfo][pydantic.fields.FieldInfo] objects.
  • __pydantic_computed_fields__: A dictionary of computed field names and their corresponding [ComputedFieldInfo][pydantic.fields.ComputedFieldInfo] objects.
  • __pydantic_extra__: A dictionary containing extra values, if [extra][pydantic.config.ConfigDict.extra] is set to 'allow'.
  • __pydantic_fields_set__: The names of fields explicitly set during instantiation.
  • __pydantic_private__: Values of private attributes set on the model instance.
model_config = {'json_encoders': {<class 'sqlglot.expressions.core.Expr'>: <function _expression_encoder>, <class 'sqlglot.expressions.datatypes.DataType'>: <function _expression_encoder>, <class 'sqlglot.expressions.query.Tuple'>: <function _expression_encoder>, typing.Union[sqlglot.expressions.query.Query, sqlmesh.core.dialect.JinjaQuery]: <function _expression_encoder>, typing.Union[sqlglot.expressions.query.Query, sqlmesh.core.dialect.JinjaQuery, sqlmesh.core.dialect.MacroFunc]: <function _expression_encoder>, <class 'datetime.tzinfo'>: <function PydanticModel.<lambda>>}, 'arbitrary_types_allowed': True, 'extra': 'forbid', 'protected_namespaces': ()}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

def dict(self, **kwargs: Any) -> Dict[str, Any]:
101    def dict(self, **kwargs: t.Any) -> t.Dict[str, t.Any]:
102        kwargs = {**DEFAULT_ARGS, **kwargs}
103        return super().model_dump(**kwargs)  # type: ignore
def json(self, **kwargs: Any) -> str:
105    def json(
106        self,
107        **kwargs: t.Any,
108    ) -> str:
109        kwargs = {**DEFAULT_ARGS, **kwargs}
110        # Pydantic v2 doesn't support arbitrary arguments for json.dump().
111        if kwargs.pop("sort_keys", False):
112            return json.dumps(super().model_dump(mode="json", **kwargs), sort_keys=True)
113
114        return super().model_dump_json(**kwargs)
def copy(self: ~Model, **kwargs: Any) -> ~Model:
116    def copy(self: "Model", **kwargs: t.Any) -> "Model":
117        return super().model_copy(**kwargs)

Returns a copy of the model.

!!! warning "Deprecated" This method is now deprecated; use model_copy instead.

If you need include or exclude, use:

python {test="skip" lint="skip"} data = self.model_dump(include=include, exclude=exclude, round_trip=True) data = {**data, **(update or {})} copied = self.model_validate(data)

Arguments:
  • include: Optional set or mapping specifying which fields to include in the copied model.
  • exclude: Optional set or mapping specifying which fields to exclude in the copied model.
  • update: Optional dictionary of field-value pairs to override field values in the copied model.
  • deep: If True, the values of fields that are Pydantic models will be deep-copied.
Returns:

A copy of the model with included, excluded and updated fields as specified.

fields_set: Set[str]
119    @property
120    def fields_set(self: "Model") -> t.Set[str]:
121        return self.__pydantic_fields_set__
@classmethod
def parse_obj(cls: Type[~Model], obj: Any) -> ~Model:
123    @classmethod
124    def parse_obj(cls: t.Type["Model"], obj: t.Any) -> "Model":
125        return super().model_validate(obj)
@classmethod
def parse_raw(cls: Type[~Model], b: Union[str, bytes], **kwargs: Any) -> ~Model:
127    @classmethod
128    def parse_raw(cls: t.Type["Model"], b: t.Union[str, bytes], **kwargs: t.Any) -> "Model":
129        return super().model_validate_json(b, **kwargs)
@classmethod
def missing_required_fields( cls: Type[PydanticModel], provided_fields: Set[str]) -> Set[str]:
131    @classmethod
132    def missing_required_fields(
133        cls: t.Type["PydanticModel"], provided_fields: t.Set[str]
134    ) -> t.Set[str]:
135        return cls.required_fields() - provided_fields
@classmethod
def extra_fields( cls: Type[PydanticModel], provided_fields: Set[str]) -> Set[str]:
137    @classmethod
138    def extra_fields(cls: t.Type["PydanticModel"], provided_fields: t.Set[str]) -> t.Set[str]:
139        return provided_fields - cls.all_fields()
@classmethod
def all_fields(cls: Type[PydanticModel]) -> Set[str]:
141    @classmethod
142    def all_fields(cls: t.Type["PydanticModel"]) -> t.Set[str]:
143        return cls._fields()
@classmethod
def all_field_infos( cls: Type[PydanticModel]) -> Dict[str, pydantic.fields.FieldInfo]:
145    @classmethod
146    def all_field_infos(cls: t.Type["PydanticModel"]) -> t.Dict[str, FieldInfo]:
147        return cls.model_fields
@classmethod
def required_fields(cls: Type[PydanticModel]) -> Set[str]:
149    @classmethod
150    def required_fields(cls: t.Type["PydanticModel"]) -> t.Set[str]:
151        return cls._fields(lambda field: field.is_required())
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
def validate_list_of_strings(v: Any) -> List[str]:
198def validate_list_of_strings(v: t.Any) -> t.List[str]:
199    if isinstance(v, exp.Identifier):
200        return [v.name]
201    if isinstance(v, (exp.Tuple, exp.Array)):
202        return [e.name for e in v.expressions]
203    return [i.name if isinstance(i, exp.Identifier) else str(i) for i in v]
def validate_string(v: Any) -> str:
206def validate_string(v: t.Any) -> str:
207    if isinstance(v, exp.Expr):
208        return v.name
209    return str(v)
def validate_expression(expression: ~E, dialect: str) -> ~E:
212def validate_expression(expression: E, dialect: str) -> E:
213    # this normalizes and quotes identifiers in the given expression according the specified dialect
214    # it also sets expression.meta["dialect"] so that when we serialize for state, the expression is serialized in the correct dialect
215    return _get_field(expression, {"dialect": dialect})  # type: ignore
def bool_validator(v: Any) -> bool:
218def bool_validator(v: t.Any) -> bool:
219    if isinstance(v, exp.Boolean):
220        return v.this
221    if isinstance(v, exp.Expr):
222        return str_to_bool(v.name)
223    return str_to_bool(str(v or ""))
def positive_int_validator(v: Any) -> int:
226def positive_int_validator(v: t.Any) -> int:
227    if isinstance(v, exp.Expr) and v.is_int:
228        v = int(v.name)
229    if not isinstance(v, int):
230        raise ValueError(f"Invalid num {v}. Value must be an integer value")
231    if v <= 0:
232        raise ValueError(f"Invalid num {v}. Value must be a positive integer")
233    return v
def validation_error_message(error: pydantic_core._pydantic_core.ValidationError, base: str) -> str:
236def validation_error_message(error: pydantic.ValidationError, base: str) -> str:
237    errors = "\n  ".join(_formatted_validation_errors(error))
238    return f"{base}\n  {errors}"
def list_of_fields_validator(v: Any, values: Any) -> List[sqlglot.expressions.core.Expr]:
296def list_of_fields_validator(v: t.Any, values: t.Any) -> t.List[exp.Expr]:
297    return _get_fields(v, values)
def column_validator(v: Any, values: Any) -> sqlglot.expressions.core.Column:
300def column_validator(v: t.Any, values: t.Any) -> exp.Column:
301    expression = _get_field(v, values)
302    if not isinstance(expression, exp.Column):
303        raise ValueError(f"Invalid column {expression}. Value must be a column")
304    return expression
def list_of_fields_or_star_validator( v: Any, values: Any) -> Union[sqlglot.expressions.core.Star, List[sqlglot.expressions.core.Expr]]:
307def list_of_fields_or_star_validator(
308    v: t.Any, values: t.Any
309) -> t.Union[exp.Star, t.List[exp.Expr]]:
310    expressions = _get_fields(v, values)
311    if len(expressions) == 1 and isinstance(expressions[0], exp.Star):
312        return t.cast(exp.Star, expressions[0])
313    return t.cast(t.List[exp.Expr], expressions)
def cron_validator(v: Any) -> str:
316def cron_validator(v: t.Any) -> str:
317    if isinstance(v, exp.Expr):
318        v = v.name
319
320    from croniter import CroniterBadCronError, croniter
321
322    if not isinstance(v, str):
323        raise ValueError(f"Invalid cron expression '{v}'. Value must be a string.")
324
325    try:
326        croniter(v)
327    except CroniterBadCronError:
328        raise ValueError(f"Invalid cron expression '{v}'")
329    return v
def get_concrete_types_from_typehint(typehint: type[typing.Any]) -> set[type[typing.Any]]:
332def get_concrete_types_from_typehint(typehint: type[t.Any]) -> set[type[t.Any]]:
333    concrete_types = set()
334    unpacked = t.get_origin(typehint)
335    if unpacked is None:
336        if type(typehint) == type(type):
337            return {typehint}
338    elif unpacked is t.Union:
339        for item in t.get_args(typehint):
340            if str(item).startswith("typing."):
341                concrete_types |= get_concrete_types_from_typehint(item)
342            else:
343                concrete_types.add(item)
344    else:
345        concrete_types.add(unpacked)
346
347    return concrete_types