codekingpro/portable-devtools
114k
1from __future__ import annotations as _annotations2 3import typing4from copy import deepcopy5from enum import Enum6from typing import Any7 8import typing_extensions9 10from .._internal import (11 _model_construction,12 _typing_extra,13 _utils,14)15 16if typing.TYPE_CHECKING:17 from .. import BaseModel18 from .._internal._utils import AbstractSetIntStr, MappingIntStrAny19 20 AnyClassMethod = classmethod[Any, Any, Any]21 TupleGenerator = typing.Generator[tuple[str, Any], None, None]22 Model = typing.TypeVar('Model', bound='BaseModel')23 # should be `set[int] | set[str] | dict[int, IncEx] | dict[str, IncEx] | None`, but mypy can't cope24 IncEx: typing_extensions.TypeAlias = 'set[int] | set[str] | dict[int, Any] | dict[str, Any] | None'25 26_object_setattr = _model_construction.object_setattr27 28 29def _iter(30 self: BaseModel,31 to_dict: bool = False,32 by_alias: bool = False,33 include: AbstractSetIntStr | MappingIntStrAny | None = None,34 exclude: AbstractSetIntStr | MappingIntStrAny | None = None,35 exclude_unset: bool = False,36 exclude_defaults: bool = False,37 exclude_none: bool = False,38) -> TupleGenerator:39 # Merge field set excludes with explicit exclude parameter with explicit overriding field set options.40 # The extra "is not None" guards are not logically necessary but optimizes performance for the simple case.41 if exclude is not None:42 exclude = _utils.ValueItems.merge(43 {k: v.exclude for k, v in self.__pydantic_fields__.items() if v.exclude is not None}, exclude44 )45 46 if include is not None:47 include = _utils.ValueItems.merge(dict.fromkeys(self.__pydantic_fields__, True), include, intersect=True)48 49 allowed_keys = _calculate_keys(self, include=include, exclude=exclude, exclude_unset=exclude_unset) # type: ignore50 if allowed_keys is None and not (to_dict or by_alias or exclude_unset or exclude_defaults or exclude_none):51 # huge boost for plain _iter()52 yield from self.__dict__.items()53 if self.__pydantic_extra__:54 yield from self.__pydantic_extra__.items()55 return56 57 value_exclude = _utils.ValueItems(self, exclude) if exclude is not None else None58 value_include = _utils.ValueItems(self, include) if include is not None else None59 60 if self.__pydantic_extra__ is None:61 items = self.__dict__.items()62 else:63 items = list(self.__dict__.items()) + list(self.__pydantic_extra__.items())64 65 for field_key, v in items:66 if (allowed_keys is not None and field_key not in allowed_keys) or (exclude_none and v is None):67 continue68 69 if exclude_defaults:70 try:71 field = self.__pydantic_fields__[field_key]72 except KeyError:73 pass74 else:75 if not field.is_required() and field.default == v:76 continue77 78 if by_alias and field_key in self.__pydantic_fields__:79 dict_key = self.__pydantic_fields__[field_key].alias or field_key80 else:81 dict_key = field_key82 83 if to_dict or value_include or value_exclude:84 v = _get_value(85 type(self),86 v,87 to_dict=to_dict,88 by_alias=by_alias,89 include=value_include and value_include.for_element(field_key),90 exclude=value_exclude and value_exclude.for_element(field_key),91 exclude_unset=exclude_unset,92 exclude_defaults=exclude_defaults,93 exclude_none=exclude_none,94 )95 yield dict_key, v96 97 98def _copy_and_set_values(99 self: Model,100 values: dict[str, Any],101 fields_set: set[str],102 extra: dict[str, Any] | None = None,103 private: dict[str, Any] | None = None,104 *,105 deep: bool, # UP006106) -> Model:107 if deep:108 # chances of having empty dict here are quite low for using smart_deepcopy109 values = deepcopy(values)110 extra = deepcopy(extra)111 private = deepcopy(private)112 113 cls = self.__class__114 m = cls.__new__(cls)115 _object_setattr(m, '__dict__', values)116 _object_setattr(m, '__pydantic_extra__', extra)117 _object_setattr(m, '__pydantic_fields_set__', fields_set)118 _object_setattr(m, '__pydantic_private__', private)119 120 return m121 122 123@typing.no_type_check124def _get_value(125 cls: type[BaseModel],126 v: Any,127 to_dict: bool,128 by_alias: bool,129 include: AbstractSetIntStr | MappingIntStrAny | None,130 exclude: AbstractSetIntStr | MappingIntStrAny | None,131 exclude_unset: bool,132 exclude_defaults: bool,133 exclude_none: bool,134) -> Any:135 from .. import BaseModel136 137 if isinstance(v, BaseModel):138 if to_dict:139 return v.model_dump(140 by_alias=by_alias,141 exclude_unset=exclude_unset,142 exclude_defaults=exclude_defaults,143 include=include, # type: ignore144 exclude=exclude, # type: ignore145 exclude_none=exclude_none,146 )147 else:148 return v.copy(include=include, exclude=exclude)149 150 value_exclude = _utils.ValueItems(v, exclude) if exclude else None151 value_include = _utils.ValueItems(v, include) if include else None152 153 if isinstance(v, dict):154 return {155 k_: _get_value(156 cls,157 v_,158 to_dict=to_dict,159 by_alias=by_alias,160 exclude_unset=exclude_unset,161 exclude_defaults=exclude_defaults,162 include=value_include and value_include.for_element(k_),163 exclude=value_exclude and value_exclude.for_element(k_),164 exclude_none=exclude_none,165 )166 for k_, v_ in v.items()167 if (not value_exclude or not value_exclude.is_excluded(k_))168 and (not value_include or value_include.is_included(k_))169 }170 171 elif _utils.sequence_like(v):172 seq_args = (173 _get_value(174 cls,175 v_,176 to_dict=to_dict,177 by_alias=by_alias,178 exclude_unset=exclude_unset,179 exclude_defaults=exclude_defaults,180 include=value_include and value_include.for_element(i),181 exclude=value_exclude and value_exclude.for_element(i),182 exclude_none=exclude_none,183 )184 for i, v_ in enumerate(v)185 if (not value_exclude or not value_exclude.is_excluded(i))186 and (not value_include or value_include.is_included(i))187 )188 189 return v.__class__(*seq_args) if _typing_extra.is_namedtuple(v.__class__) else v.__class__(seq_args)190 191 elif isinstance(v, Enum) and getattr(cls.model_config, 'use_enum_values', False):192 return v.value193 194 else:195 return v196 197 198def _calculate_keys(199 self: BaseModel,200 include: MappingIntStrAny | None,201 exclude: MappingIntStrAny | None,202 exclude_unset: bool,203 update: dict[str, Any] | None = None, # noqa UP006204) -> typing.AbstractSet[str] | None:205 if include is None and exclude is None and exclude_unset is False:206 return None207 208 keys: typing.AbstractSet[str]209 if exclude_unset:210 keys = self.__pydantic_fields_set__.copy()211 else:212 keys = set(self.__dict__.keys())213 keys = keys | (self.__pydantic_extra__ or {}).keys()214 215 if include is not None:216 keys &= include.keys()217 218 if update:219 keys -= update.keys()220 221 if exclude:222 keys -= {k for k, v in exclude.items() if _utils.ValueItems.is_true(v)}223 224 return keys225 