1import json 2import sys 3import warnings 4from abc import ABCMeta 5from copy import deepcopy 6from enum import Enum 7from functools import partial 8from pathlib import Path 9from types import FunctionType 10from typing import ( 11 TYPE_CHECKING, 12 AbstractSet, 13 Any, 14 Callable, 15 Dict, 16 List, 17 Mapping, 18 Optional, 19 Tuple, 20 Type, 21 TypeVar, 22 Union, 23 cast, 24 no_type_check, 25 overload, 26) 27 28from .class_validators import ValidatorGroup, extract_root_validators, extract_validators, inherit_validators 29from .error_wrappers import ErrorWrapper, ValidationError 30from .errors import ConfigError, DictError, ExtraError, MissingError 31from .fields import MAPPING_LIKE_SHAPES, ModelField, ModelPrivateAttr, PrivateAttr, Undefined 32from .json import custom_pydantic_encoder, pydantic_encoder 33from .parse import Protocol, load_file, load_str_bytes 34from .schema import default_ref_template, model_schema 35from .types import PyObject, StrBytes 36from .typing import ( 37 AnyCallable, 38 get_args, 39 get_origin, 40 is_classvar, 41 is_namedtuple, 42 resolve_annotations, 43 update_field_forward_refs, 44) 45from .utils import ( 46 ROOT_KEY, 47 ClassAttribute, 48 GetterDict, 49 Representation, 50 ValueItems, 51 generate_model_signature, 52 is_valid_field, 53 is_valid_private_name, 54 lenient_issubclass, 55 sequence_like, 56 smart_deepcopy, 57 unique_list, 58 validate_field_name, 59) 60 61if TYPE_CHECKING: 62 from inspect import Signature 63 64 import typing_extensions 65 66 from .class_validators import ValidatorListDict 67 from .types import ModelOrDc 68 from .typing import ( # noqa: F401 69 AbstractSetIntStr, 70 CallableGenerator, 71 DictAny, 72 DictStrAny, 73 MappingIntStrAny, 74 ReprArgs, 75 SetStr, 76 TupleGenerator, 77 ) 78 79 ConfigType = Type['BaseConfig'] 80 Model = TypeVar('Model', bound='BaseModel') 81 82 class SchemaExtraCallable(typing_extensions.Protocol): 83 @overload 84 def __call__(self, schema: Dict[str, Any]) -> None: 85 pass 86 87 @overload # noqa: F811 88 def __call__(self, schema: Dict[str, Any], model_class: Type['Model']) -> None: # noqa: F811 89 pass 90 91 92else: 93 SchemaExtraCallable = Callable[..., None] 94 95try: 96 import cython # type: ignore 97except ImportError: 98 compiled: bool = False 99else: # pragma: no cover 100 try: 101 compiled = cython.compiled 102 except AttributeError: 103 compiled = False 104 105__all__ = 'BaseConfig', 'BaseModel', 'Extra', 'compiled', 'create_model', 'validate_model' 106 107 108class Extra(str, Enum): 109 allow = 'allow' 110 ignore = 'ignore' 111 forbid = 'forbid' 112 113 114class BaseConfig: 115 title = None 116 anystr_lower = False 117 anystr_strip_whitespace = False 118 min_anystr_length = None 119 max_anystr_length = None 120 validate_all = False 121 extra = Extra.ignore 122 allow_mutation = True 123 frozen = False 124 allow_population_by_field_name = False 125 use_enum_values = False 126 fields: Dict[str, Union[str, Dict[str, str]]] = {} 127 validate_assignment = False 128 error_msg_templates: Dict[str, str] = {} 129 arbitrary_types_allowed = False 130 orm_mode: bool = False 131 getter_dict: Type[GetterDict] = GetterDict 132 alias_generator: Optional[Callable[[str], str]] = None 133 keep_untouched: Tuple[type, ...] = () 134 schema_extra: Union[Dict[str, Any], 'SchemaExtraCallable'] = {} 135 json_loads: Callable[[str], Any] = json.loads 136 json_dumps: Callable[..., str] = json.dumps 137 json_encoders: Dict[Type[Any], AnyCallable] = {} 138 underscore_attrs_are_private: bool = False 139 140 # Whether or not inherited models as fields should be reconstructed as base model 141 copy_on_model_validation: bool = True 142 143 @classmethod 144 def get_field_info(cls, name: str) -> Dict[str, Any]: 145 """ 146 Get properties of FieldInfo from the `fields` property of the config class. 147 """ 148 149 fields_value = cls.fields.get(name) 150 151 if isinstance(fields_value, str): 152 field_info: Dict[str, Any] = {'alias': fields_value} 153 elif isinstance(fields_value, dict): 154 field_info = fields_value 155 else: 156 field_info = {} 157 158 if 'alias' in field_info: 159 field_info.setdefault('alias_priority', 2) 160 161 if field_info.get('alias_priority', 0) <= 1 and cls.alias_generator: 162 alias = cls.alias_generator(name) 163 if not isinstance(alias, str): 164 raise TypeError(f'Config.alias_generator must return str, not {alias.__class__}') 165 field_info.update(alias=alias, alias_priority=1) 166 return field_info 167 168 @classmethod 169 def prepare_field(cls, field: 'ModelField') -> None: 170 """ 171 Optional hook to check or modify fields during model creation. 172 """ 173 pass 174 175 176def inherit_config(self_config: 'ConfigType', parent_config: 'ConfigType', **namespace: Any) -> 'ConfigType': 177 if not self_config: 178 base_classes: Tuple['ConfigType', ...] = (parent_config,) 179 elif self_config == parent_config: 180 base_classes = (self_config,) 181 else: 182 base_classes = self_config, parent_config 183 184 namespace['json_encoders'] = { 185 **getattr(parent_config, 'json_encoders', {}), 186 **getattr(self_config, 'json_encoders', {}), 187 **namespace.get('json_encoders', {}), 188 } 189 190 return type('Config', base_classes, namespace) 191 192 193EXTRA_LINK = 'https://pydantic-docs.helpmanual.io/usage/model_config/' 194 195 196def prepare_config(config: Type[BaseConfig], cls_name: str) -> None: 197 if not isinstance(config.extra, Extra): 198 try: 199 config.extra = Extra(config.extra) 200 except ValueError: 201 raise ValueError(f'"{cls_name}": {config.extra} is not a valid value for "extra"') 202 203 204def validate_custom_root_type(fields: Dict[str, ModelField]) -> None: 205 if len(fields) > 1: 206 raise ValueError(f'{ROOT_KEY} cannot be mixed with other fields') 207 208 209def generate_hash_function(frozen: bool) -> Optional[Callable[[Any], int]]: 210 def hash_function(self_: Any) -> int: 211 return hash(self_.__class__) + hash(tuple(self_.__dict__.values())) 212 213 return hash_function if frozen else None 214 215 216# If a field is of type `Callable`, its default value should be a function and cannot to ignored. 217ANNOTATED_FIELD_UNTOUCHED_TYPES: Tuple[Any, ...] = (property, type, classmethod, staticmethod) 218# When creating a `BaseModel` instance, we bypass all the methods, properties... added to the model 219UNTOUCHED_TYPES: Tuple[Any, ...] = (FunctionType,) + ANNOTATED_FIELD_UNTOUCHED_TYPES 220# Note `ModelMetaclass` refers to `BaseModel`, but is also used to *create* `BaseModel`, so we need to add this extra 221# (somewhat hacky) boolean to keep track of whether we've created the `BaseModel` class yet, and therefore whether it's 222# safe to refer to it. If it *hasn't* been created, we assume that the `__new__` call we're in the middle of is for 223# the `BaseModel` class, since that's defined immediately after the metaclass. 224_is_base_model_class_defined = False 225 226 227class ModelMetaclass(ABCMeta): 228 @no_type_check # noqa C901 229 def __new__(mcs, name, bases, namespace, **kwargs): # noqa C901 230 fields: Dict[str, ModelField] = {} 231 config = BaseConfig 232 validators: 'ValidatorListDict' = {} 233 234 pre_root_validators, post_root_validators = [], [] 235 private_attributes: Dict[str, ModelPrivateAttr] = {} 236 slots: SetStr = namespace.get('__slots__', ()) 237 slots = {slots} if isinstance(slots, str) else set(slots) 238 class_vars: SetStr = set() 239 hash_func: Optional[Callable[[Any], int]] = None 240 241 for base in reversed(bases): 242 if _is_base_model_class_defined and issubclass(base, BaseModel) and base != BaseModel: 243 fields.update(smart_deepcopy(base.__fields__)) 244 config = inherit_config(base.__config__, config) 245 validators = inherit_validators(base.__validators__, validators) 246 pre_root_validators += base.__pre_root_validators__ 247 post_root_validators += base.__post_root_validators__ 248 private_attributes.update(base.__private_attributes__) 249 class_vars.update(base.__class_vars__) 250 hash_func = base.__hash__ 251 252 allowed_config_kwargs: SetStr = { 253 key 254 for key in dir(config) 255 if not (key.startswith('__') and key.endswith('__')) # skip dunder methods and attributes 256 } 257 config_kwargs = {key: kwargs.pop(key) for key in kwargs.keys() & allowed_config_kwargs} 258 config_from_namespace = namespace.get('Config') 259 if config_kwargs and config_from_namespace: 260 raise TypeError('Specifying config in two places is ambiguous, use either Config attribute or class kwargs') 261 config = inherit_config(config_from_namespace, config, **config_kwargs) 262 263 validators = inherit_validators(extract_validators(namespace), validators) 264 vg = ValidatorGroup(validators) 265 266 for f in fields.values(): 267 f.set_config(config) 268 extra_validators = vg.get_validators(f.name) 269 if extra_validators: 270 f.class_validators.update(extra_validators) 271 # re-run prepare to add extra validators 272 f.populate_validators() 273 274 prepare_config(config, name) 275 276 untouched_types = ANNOTATED_FIELD_UNTOUCHED_TYPES 277 278 def is_untouched(v: Any) -> bool: 279 return isinstance(v, untouched_types) or v.__class__.__name__ == 'cython_function_or_method' 280 281 if (namespace.get('__module__'), namespace.get('__qualname__')) != ('pydantic.main', 'BaseModel'): 282 annotations = resolve_annotations(namespace.get('__annotations__', {}), namespace.get('__module__', None)) 283 # annotation only fields need to come first in fields 284 for ann_name, ann_type in annotations.items(): 285 if is_classvar(ann_type): 286 class_vars.add(ann_name) 287 elif is_valid_field(ann_name): 288 validate_field_name(bases, ann_name) 289 value = namespace.get(ann_name, Undefined) 290 allowed_types = get_args(ann_type) if get_origin(ann_type) is Union else (ann_type,) 291 if ( 292 is_untouched(value) 293 and ann_type != PyObject 294 and not any( 295 lenient_issubclass(get_origin(allowed_type), Type) for allowed_type in allowed_types 296 ) 297 ): 298 continue 299 fields[ann_name] = ModelField.infer( 300 name=ann_name, 301 value=value, 302 annotation=ann_type, 303 class_validators=vg.get_validators(ann_name), 304 config=config, 305 ) 306 elif ann_name not in namespace and config.underscore_attrs_are_private: 307 private_attributes[ann_name] = PrivateAttr() 308 309 untouched_types = UNTOUCHED_TYPES + config.keep_untouched 310 for var_name, value in namespace.items(): 311 can_be_changed = var_name not in class_vars and not is_untouched(value) 312 if isinstance(value, ModelPrivateAttr): 313 if not is_valid_private_name(var_name): 314 raise NameError( 315 f'Private attributes "{var_name}" must not be a valid field name; ' 316 f'Use sunder or dunder names, e. g. "_{var_name}" or "__{var_name}__"' 317 ) 318 private_attributes[var_name] = value 319 elif config.underscore_attrs_are_private and is_valid_private_name(var_name) and can_be_changed: 320 private_attributes[var_name] = PrivateAttr(default=value) 321 elif is_valid_field(var_name) and var_name not in annotations and can_be_changed: 322 validate_field_name(bases, var_name) 323 inferred = ModelField.infer( 324 name=var_name, 325 value=value, 326 annotation=annotations.get(var_name, Undefined), 327 class_validators=vg.get_validators(var_name), 328 config=config, 329 ) 330 if var_name in fields and inferred.type_ != fields[var_name].type_: 331 raise TypeError( 332 f'The type of {name}.{var_name} differs from the new default value; ' 333 f'if you wish to change the type of this field, please use a type annotation' 334 ) 335 fields[var_name] = inferred 336 337 _custom_root_type = ROOT_KEY in fields 338 if _custom_root_type: 339 validate_custom_root_type(fields) 340 vg.check_for_unused() 341 if config.json_encoders: 342 json_encoder = partial(custom_pydantic_encoder, config.json_encoders) 343 else: 344 json_encoder = pydantic_encoder 345 pre_rv_new, post_rv_new = extract_root_validators(namespace) 346 347 if hash_func is None: 348 hash_func = generate_hash_function(config.frozen) 349 350 exclude_from_namespace = fields | private_attributes.keys() | {'__slots__'} 351 new_namespace = { 352 '__config__': config, 353 '__fields__': fields, 354 '__validators__': vg.validators, 355 '__pre_root_validators__': unique_list(pre_root_validators + pre_rv_new), 356 '__post_root_validators__': unique_list(post_root_validators + post_rv_new), 357 '__schema_cache__': {}, 358 '__json_encoder__': staticmethod(json_encoder), 359 '__custom_root_type__': _custom_root_type, 360 '__private_attributes__': private_attributes, 361 '__slots__': slots | private_attributes.keys(), 362 '__hash__': hash_func, 363 '__class_vars__': class_vars, 364 **{n: v for n, v in namespace.items() if n not in exclude_from_namespace}, 365 } 366 367 cls = super().__new__(mcs, name, bases, new_namespace, **kwargs) 368 # set __signature__ attr only for model class, but not for its instances 369 cls.__signature__ = ClassAttribute('__signature__', generate_model_signature(cls.__init__, fields, config)) 370 return cls 371 372 373object_setattr = object.__setattr__ 374 375 376class BaseModel(Representation, metaclass=ModelMetaclass): 377 if TYPE_CHECKING: 378 # populated by the metaclass, defined here to help IDEs only 379 __fields__: Dict[str, ModelField] = {} 380 __validators__: Dict[str, AnyCallable] = {} 381 __pre_root_validators__: List[AnyCallable] 382 __post_root_validators__: List[Tuple[bool, AnyCallable]] 383 __config__: Type[BaseConfig] = BaseConfig 384 __root__: Any = None 385 __json_encoder__: Callable[[Any], Any] = lambda x: x 386 __schema_cache__: 'DictAny' = {} 387 __custom_root_type__: bool = False 388 __signature__: 'Signature' 389 __private_attributes__: Dict[str, Any] 390 __class_vars__: SetStr 391 __fields_set__: SetStr = set() 392 393 Config = BaseConfig 394 __slots__ = ('__dict__', '__fields_set__') 395 __doc__ = '' # Null out the Representation docstring 396 397 def __init__(__pydantic_self__, **data: Any) -> None: 398 """ 399 Create a new model by parsing and validating input data from keyword arguments. 400 401 Raises ValidationError if the input data cannot be parsed to form a valid model. 402 """ 403 # Uses something other than `self` the first arg to allow "self" as a settable attribute 404 values, fields_set, validation_error = validate_model(__pydantic_self__.__class__, data) 405 if validation_error: 406 raise validation_error 407 try: 408 object_setattr(__pydantic_self__, '__dict__', values) 409 except TypeError as e: 410 raise TypeError( 411 'Model values must be a dict; you may not have returned a dictionary from a root validator' 412 ) from e 413 object_setattr(__pydantic_self__, '__fields_set__', fields_set) 414 __pydantic_self__._init_private_attributes() 415 416 @no_type_check 417 def __setattr__(self, name, value): # noqa: C901 (ignore complexity) 418 if name in self.__private_attributes__: 419 return object_setattr(self, name, value) 420 421 if self.__config__.extra is not Extra.allow and name not in self.__fields__: 422 raise ValueError(f'"{self.__class__.__name__}" object has no field "{name}"') 423 elif not self.__config__.allow_mutation or self.__config__.frozen: 424 raise TypeError(f'"{self.__class__.__name__}" is immutable and does not support item assignment') 425 elif self.__config__.validate_assignment: 426 new_values = {**self.__dict__, name: value} 427 428 for validator in self.__pre_root_validators__: 429 try: 430 new_values = validator(self.__class__, new_values) 431 except (ValueError, TypeError, AssertionError) as exc: 432 raise ValidationError([ErrorWrapper(exc, loc=ROOT_KEY)], self.__class__) 433 434 known_field = self.__fields__.get(name, None) 435 if known_field: 436 # We want to 437 # - make sure validators are called without the current value for this field inside `values` 438 # - keep other values (e.g. submodels) untouched (using `BaseModel.dict()` will change them into dicts) 439 # - keep the order of the fields 440 if not known_field.field_info.allow_mutation: 441 raise TypeError(f'"{known_field.name}" has allow_mutation set to False and cannot be assigned') 442 dict_without_original_value = {k: v for k, v in self.__dict__.items() if k != name} 443 value, error_ = known_field.validate(value, dict_without_original_value, loc=name, cls=self.__class__) 444 if error_: 445 raise ValidationError([error_], self.__class__) 446 else: 447 new_values[name] = value 448 449 errors = [] 450 for skip_on_failure, validator in self.__post_root_validators__: 451 if skip_on_failure and errors: 452 continue 453 try: 454 new_values = validator(self.__class__, new_values) 455 except (ValueError, TypeError, AssertionError) as exc: 456 errors.append(ErrorWrapper(exc, loc=ROOT_KEY)) 457 if errors: 458 raise ValidationError(errors, self.__class__) 459 460 # update the whole __dict__ as other values than just `value` 461 # may be changed (e.g. with `root_validator`) 462 object_setattr(self, '__dict__', new_values) 463 else: 464 self.__dict__[name] = value 465 466 self.__fields_set__.add(name) 467 468 def __getstate__(self) -> 'DictAny': 469 private_attrs = ((k, getattr(self, k, Undefined)) for k in self.__private_attributes__) 470 return { 471 '__dict__': self.__dict__, 472 '__fields_set__': self.__fields_set__, 473 '__private_attribute_values__': {k: v for k, v in private_attrs if v is not Undefined}, 474 } 475 476 def __setstate__(self, state: 'DictAny') -> None: 477 object_setattr(self, '__dict__', state['__dict__']) 478 object_setattr(self, '__fields_set__', state['__fields_set__']) 479 for name, value in state.get('__private_attribute_values__', {}).items(): 480 object_setattr(self, name, value) 481 482 def _init_private_attributes(self) -> None: 483 for name, private_attr in self.__private_attributes__.items(): 484 default = private_attr.get_default() 485 if default is not Undefined: 486 object_setattr(self, name, default) 487 488 def dict( 489 self, 490 *, 491 include: Union['AbstractSetIntStr', 'MappingIntStrAny'] = None, 492 exclude: Union['AbstractSetIntStr', 'MappingIntStrAny'] = None, 493 by_alias: bool = False, 494 skip_defaults: bool = None, 495 exclude_unset: bool = False, 496 exclude_defaults: bool = False, 497 exclude_none: bool = False, 498 ) -> 'DictStrAny': 499 """ 500 Generate a dictionary representation of the model, optionally specifying which fields to include or exclude. 501 502 """ 503 if skip_defaults is not None: 504 warnings.warn( 505 f'{self.__class__.__name__}.dict(): "skip_defaults" is deprecated and replaced by "exclude_unset"', 506 DeprecationWarning, 507 ) 508 exclude_unset = skip_defaults 509 510 return dict( 511 self._iter( 512 to_dict=True, 513 by_alias=by_alias, 514 include=include, 515 exclude=exclude, 516 exclude_unset=exclude_unset, 517 exclude_defaults=exclude_defaults, 518 exclude_none=exclude_none, 519 ) 520 ) 521 522 def json( 523 self, 524 *, 525 include: Union['AbstractSetIntStr', 'MappingIntStrAny'] = None, 526 exclude: Union['AbstractSetIntStr', 'MappingIntStrAny'] = None, 527 by_alias: bool = False, 528 skip_defaults: bool = None, 529 exclude_unset: bool = False, 530 exclude_defaults: bool = False, 531 exclude_none: bool = False, 532 encoder: Optional[Callable[[Any], Any]] = None, 533 **dumps_kwargs: Any, 534 ) -> str: 535 """ 536 Generate a JSON representation of the model, `include` and `exclude` arguments as per `dict()`. 537 538 `encoder` is an optional function to supply as `default` to json.dumps(), other arguments as per `json.dumps()`. 539 """ 540 if skip_defaults is not None: 541 warnings.warn( 542 f'{self.__class__.__name__}.json(): "skip_defaults" is deprecated and replaced by "exclude_unset"', 543 DeprecationWarning, 544 ) 545 exclude_unset = skip_defaults 546 encoder = cast(Callable[[Any], Any], encoder or self.__json_encoder__) 547 data = self.dict( 548 include=include, 549 exclude=exclude, 550 by_alias=by_alias, 551 exclude_unset=exclude_unset, 552 exclude_defaults=exclude_defaults, 553 exclude_none=exclude_none, 554 ) 555 if self.__custom_root_type__: 556 data = data[ROOT_KEY] 557 return self.__config__.json_dumps(data, default=encoder, **dumps_kwargs) 558 559 @classmethod 560 def _enforce_dict_if_root(cls, obj: Any) -> Any: 561 if cls.__custom_root_type__ and ( 562 not (isinstance(obj, dict) and obj.keys() == {ROOT_KEY}) 563 or cls.__fields__[ROOT_KEY].shape in MAPPING_LIKE_SHAPES 564 ): 565 return {ROOT_KEY: obj} 566 else: 567 return obj 568 569 @classmethod 570 def parse_obj(cls: Type['Model'], obj: Any) -> 'Model': 571 obj = cls._enforce_dict_if_root(obj) 572 if not isinstance(obj, dict): 573 try: 574 obj = dict(obj) 575 except (TypeError, ValueError) as e: 576 exc = TypeError(f'{cls.__name__} expected dict not {obj.__class__.__name__}') 577 raise ValidationError([ErrorWrapper(exc, loc=ROOT_KEY)], cls) from e 578 return cls(**obj) 579 580 @classmethod 581 def parse_raw( 582 cls: Type['Model'], 583 b: StrBytes, 584 *, 585 content_type: str = None, 586 encoding: str = 'utf8', 587 proto: Protocol = None, 588 allow_pickle: bool = False, 589 ) -> 'Model': 590 try: 591 obj = load_str_bytes( 592 b, 593 proto=proto, 594 content_type=content_type, 595 encoding=encoding, 596 allow_pickle=allow_pickle, 597 json_loads=cls.__config__.json_loads, 598 ) 599 except (ValueError, TypeError, UnicodeDecodeError) as e: 600 raise ValidationError([ErrorWrapper(e, loc=ROOT_KEY)], cls) 601 return cls.parse_obj(obj) 602 603 @classmethod 604 def parse_file( 605 cls: Type['Model'], 606 path: Union[str, Path], 607 *, 608 content_type: str = None, 609 encoding: str = 'utf8', 610 proto: Protocol = None, 611 allow_pickle: bool = False, 612 ) -> 'Model': 613 obj = load_file( 614 path, 615 proto=proto, 616 content_type=content_type, 617 encoding=encoding, 618 allow_pickle=allow_pickle, 619 json_loads=cls.__config__.json_loads, 620 ) 621 return cls.parse_obj(obj) 622 623 @classmethod 624 def from_orm(cls: Type['Model'], obj: Any) -> 'Model': 625 if not cls.__config__.orm_mode: 626 raise ConfigError('You must have the config attribute orm_mode=True to use from_orm') 627 obj = {ROOT_KEY: obj} if cls.__custom_root_type__ else cls._decompose_class(obj) 628 m = cls.__new__(cls) 629 values, fields_set, validation_error = validate_model(cls, obj) 630 if validation_error: 631 raise validation_error 632 object_setattr(m, '__dict__', values) 633 object_setattr(m, '__fields_set__', fields_set) 634 m._init_private_attributes() 635 return m 636 637 @classmethod 638 def construct(cls: Type['Model'], _fields_set: Optional['SetStr'] = None, **values: Any) -> 'Model': 639 """ 640 Creates a new model setting __dict__ and __fields_set__ from trusted or pre-validated data. 641 Default values are respected, but no other validation is performed. 642 Behaves as if `Config.extra = 'allow'` was set since it adds all passed values 643 """ 644 m = cls.__new__(cls) 645 fields_values: Dict[str, Any] = {} 646 for name, field in cls.__fields__.items(): 647 if name in values: 648 fields_values[name] = values[name] 649 elif not field.required: 650 fields_values[name] = field.get_default() 651 fields_values.update(values) 652 object_setattr(m, '__dict__', fields_values) 653 if _fields_set is None: 654 _fields_set = set(values.keys()) 655 object_setattr(m, '__fields_set__', _fields_set) 656 m._init_private_attributes() 657 return m 658 659 def copy( 660 self: 'Model', 661 *, 662 include: Union['AbstractSetIntStr', 'MappingIntStrAny'] = None, 663 exclude: Union['AbstractSetIntStr', 'MappingIntStrAny'] = None, 664 update: 'DictStrAny' = None, 665 deep: bool = False, 666 ) -> 'Model': 667 """ 668 Duplicate a model, optionally choose which fields to include, exclude and change. 669 670 :param include: fields to include in new model 671 :param exclude: fields to exclude from new model, as with values this takes precedence over include 672 :param update: values to change/add in the new model. Note: the data is not validated before creating 673 the new model: you should trust this data 674 :param deep: set to `True` to make a deep copy of the model 675 :return: new model instance 676 """ 677 678 v = dict( 679 self._iter(to_dict=False, by_alias=False, include=include, exclude=exclude, exclude_unset=False), 680 **(update or {}), 681 ) 682 683 if deep: 684 # chances of having empty dict here are quite low for using smart_deepcopy 685 v = deepcopy(v) 686 687 cls = self.__class__ 688 m = cls.__new__(cls) 689 object_setattr(m, '__dict__', v) 690 # new `__fields_set__` can have unset optional fields with a set value in `update` kwarg 691 if update: 692 fields_set = self.__fields_set__ | update.keys() 693 else: 694 fields_set = set(self.__fields_set__) 695 object_setattr(m, '__fields_set__', fields_set) 696 for name in self.__private_attributes__: 697 value = getattr(self, name, Undefined) 698 if value is not Undefined: 699 if deep: 700 value = deepcopy(value) 701 object_setattr(m, name, value) 702 703 return m 704 705 @classmethod 706 def schema(cls, by_alias: bool = True, ref_template: str = default_ref_template) -> 'DictStrAny': 707 cached = cls.__schema_cache__.get((by_alias, ref_template)) 708 if cached is not None: 709 return cached 710 s = model_schema(cls, by_alias=by_alias, ref_template=ref_template) 711 cls.__schema_cache__[(by_alias, ref_template)] = s 712 return s 713 714 @classmethod 715 def schema_json( 716 cls, *, by_alias: bool = True, ref_template: str = default_ref_template, **dumps_kwargs: Any 717 ) -> str: 718 from .json import pydantic_encoder 719 720 return cls.__config__.json_dumps( 721 cls.schema(by_alias=by_alias, ref_template=ref_template), default=pydantic_encoder, **dumps_kwargs 722 ) 723 724 @classmethod 725 def __get_validators__(cls) -> 'CallableGenerator': 726 yield cls.validate 727 728 @classmethod 729 def validate(cls: Type['Model'], value: Any) -> 'Model': 730 if isinstance(value, cls): 731 return value.copy() if cls.__config__.copy_on_model_validation else value 732 733 value = cls._enforce_dict_if_root(value) 734 if isinstance(value, dict): 735 return cls(**value) 736 elif cls.__config__.orm_mode: 737 return cls.from_orm(value) 738 else: 739 try: 740 value_as_dict = dict(value) 741 except (TypeError, ValueError) as e: 742 raise DictError() from e 743 return cls(**value_as_dict) 744 745 @classmethod 746 def _decompose_class(cls: Type['Model'], obj: Any) -> GetterDict: 747 return cls.__config__.getter_dict(obj) 748 749 @classmethod 750 @no_type_check 751 def _get_value( 752 cls, 753 v: Any, 754 to_dict: bool, 755 by_alias: bool, 756 include: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']], 757 exclude: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']], 758 exclude_unset: bool, 759 exclude_defaults: bool, 760 exclude_none: bool, 761 ) -> Any: 762 763 if isinstance(v, BaseModel): 764 if to_dict: 765 v_dict = v.dict( 766 by_alias=by_alias, 767 exclude_unset=exclude_unset, 768 exclude_defaults=exclude_defaults, 769 include=include, 770 exclude=exclude, 771 exclude_none=exclude_none, 772 ) 773 if ROOT_KEY in v_dict: 774 return v_dict[ROOT_KEY] 775 return v_dict 776 else: 777 return v.copy(include=include, exclude=exclude) 778 779 value_exclude = ValueItems(v, exclude) if exclude else None 780 value_include = ValueItems(v, include) if include else None 781 782 if isinstance(v, dict): 783 return { 784 k_: cls._get_value( 785 v_, 786 to_dict=to_dict, 787 by_alias=by_alias, 788 exclude_unset=exclude_unset, 789 exclude_defaults=exclude_defaults, 790 include=value_include and value_include.for_element(k_), 791 exclude=value_exclude and value_exclude.for_element(k_), 792 exclude_none=exclude_none, 793 ) 794 for k_, v_ in v.items() 795 if (not value_exclude or not value_exclude.is_excluded(k_)) 796 and (not value_include or value_include.is_included(k_)) 797 } 798 799 elif sequence_like(v): 800 seq_args = ( 801 cls._get_value( 802 v_, 803 to_dict=to_dict, 804 by_alias=by_alias, 805 exclude_unset=exclude_unset, 806 exclude_defaults=exclude_defaults, 807 include=value_include and value_include.for_element(i), 808 exclude=value_exclude and value_exclude.for_element(i), 809 exclude_none=exclude_none, 810 ) 811 for i, v_ in enumerate(v) 812 if (not value_exclude or not value_exclude.is_excluded(i)) 813 and (not value_include or value_include.is_included(i)) 814 ) 815 816 return v.__class__(*seq_args) if is_namedtuple(v.__class__) else v.__class__(seq_args) 817 818 elif isinstance(v, Enum) and getattr(cls.Config, 'use_enum_values', False): 819 return v.value 820 821 else: 822 return v 823 824 @classmethod 825 def update_forward_refs(cls, **localns: Any) -> None: 826 """ 827 Try to update ForwardRefs on fields based on this Model, globalns and localns. 828 """ 829 globalns = sys.modules[cls.__module__].__dict__.copy() 830 globalns.setdefault(cls.__name__, cls) 831 for f in cls.__fields__.values(): 832 update_field_forward_refs(f, globalns=globalns, localns=localns) 833 834 def __iter__(self) -> 'TupleGenerator': 835 """ 836 so `dict(model)` works 837 """ 838 yield from self.__dict__.items() 839 840 def _iter( 841 self, 842 to_dict: bool = False, 843 by_alias: bool = False, 844 include: Union['AbstractSetIntStr', 'MappingIntStrAny'] = None, 845 exclude: Union['AbstractSetIntStr', 'MappingIntStrAny'] = None, 846 exclude_unset: bool = False, 847 exclude_defaults: bool = False, 848 exclude_none: bool = False, 849 ) -> 'TupleGenerator': 850 851 allowed_keys = self._calculate_keys(include=include, exclude=exclude, exclude_unset=exclude_unset) 852 if allowed_keys is None and not (to_dict or by_alias or exclude_unset or exclude_defaults or exclude_none): 853 # huge boost for plain _iter() 854 yield from self.__dict__.items() 855 return 856 857 value_exclude = ValueItems(self, exclude) if exclude else None 858 value_include = ValueItems(self, include) if include else None 859 860 for field_key, v in self.__dict__.items(): 861 if (allowed_keys is not None and field_key not in allowed_keys) or (exclude_none and v is None): 862 continue 863 864 if exclude_defaults: 865 model_field = self.__fields__.get(field_key) 866 if not getattr(model_field, 'required', True) and getattr(model_field, 'default', _missing) == v: 867 continue 868 869 if by_alias and field_key in self.__fields__: 870 dict_key = self.__fields__[field_key].alias 871 else: 872 dict_key = field_key 873 874 if to_dict or value_include or value_exclude: 875 v = self._get_value( 876 v, 877 to_dict=to_dict, 878 by_alias=by_alias, 879 include=value_include and value_include.for_element(field_key), 880 exclude=value_exclude and value_exclude.for_element(field_key), 881 exclude_unset=exclude_unset, 882 exclude_defaults=exclude_defaults, 883 exclude_none=exclude_none, 884 ) 885 yield dict_key, v 886 887 def _calculate_keys( 888 self, 889 include: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']], 890 exclude: Optional[Union['AbstractSetIntStr', 'MappingIntStrAny']], 891 exclude_unset: bool, 892 update: Optional['DictStrAny'] = None, 893 ) -> Optional[AbstractSet[str]]: 894 if include is None and exclude is None and exclude_unset is False: 895 return None 896 897 keys: AbstractSet[str] 898 if exclude_unset: 899 keys = self.__fields_set__.copy() 900 else: 901 keys = self.__dict__.keys() 902 903 if include is not None: 904 if isinstance(include, Mapping): 905 keys &= include.keys() 906 else: 907 keys &= include 908 909 if update: 910 keys -= update.keys() 911 912 if exclude: 913 if isinstance(exclude, Mapping): 914 keys -= {k for k, v in exclude.items() if v is ...} 915 else: 916 keys -= exclude 917 918 return keys 919 920 def __eq__(self, other: Any) -> bool: 921 if isinstance(other, BaseModel): 922 return self.dict() == other.dict() 923 else: 924 return self.dict() == other 925 926 def __repr_args__(self) -> 'ReprArgs': 927 return self.__dict__.items() # type: ignore 928 929 930_is_base_model_class_defined = True 931 932 933def create_model( 934 __model_name: str, 935 *, 936 __config__: Type[BaseConfig] = None, 937 __base__: Type['Model'] = None, 938 __module__: str = __name__, 939 __validators__: Dict[str, classmethod] = None, 940 **field_definitions: Any, 941) -> Type['Model']: 942 """ 943 Dynamically create a model. 944 :param __model_name: name of the created model 945 :param __config__: config class to use for the new model 946 :param __base__: base class for the new model to inherit from 947 :param __module__: module of the created model 948 :param __validators__: a dict of method names and @validator class methods 949 :param field_definitions: fields of the model (or extra fields if a base is supplied) 950 in the format `<name>=(<type>, <default default>)` or `<name>=<default value>, e.g. 951 `foobar=(str, ...)` or `foobar=123`, or, for complex use-cases, in the format 952 `<name>=<FieldInfo>`, e.g. `foo=Field(default_factory=datetime.utcnow, alias='bar')` 953 """ 954 955 if __base__ is not None: 956 if __config__ is not None: 957 raise ConfigError('to avoid confusion __config__ and __base__ cannot be used together') 958 else: 959 __base__ = cast(Type['Model'], BaseModel) 960 961 fields = {} 962 annotations = {} 963 964 for f_name, f_def in field_definitions.items(): 965 if not is_valid_field(f_name): 966 warnings.warn(f'fields may not start with an underscore, ignoring "{f_name}"', RuntimeWarning) 967 if isinstance(f_def, tuple): 968 try: 969 f_annotation, f_value = f_def 970 except ValueError as e: 971 raise ConfigError( 972 'field definitions should either be a tuple of (<type>, <default>) or just a ' 973 'default value, unfortunately this means tuples as ' 974 'default values are not allowed' 975 ) from e 976 else: 977 f_annotation, f_value = None, f_def 978 979 if f_annotation: 980 annotations[f_name] = f_annotation 981 fields[f_name] = f_value 982 983 namespace: 'DictStrAny' = {'__annotations__': annotations, '__module__': __module__} 984 if __validators__: 985 namespace.update(__validators__) 986 namespace.update(fields) 987 if __config__: 988 namespace['Config'] = inherit_config(__config__, BaseConfig) 989 990 return type(__model_name, (__base__,), namespace) 991 992 993_missing = object() 994 995 996def validate_model( # noqa: C901 (ignore complexity) 997 model: Type[BaseModel], input_data: 'DictStrAny', cls: 'ModelOrDc' = None 998) -> Tuple['DictStrAny', 'SetStr', Optional[ValidationError]]: 999 """ 1000 validate data against a model. 1001 """ 1002 values = {} 1003 errors = [] 1004 # input_data names, possibly alias 1005 names_used = set() 1006 # field names, never aliases 1007 fields_set = set() 1008 config = model.__config__ 1009 check_extra = config.extra is not Extra.ignore 1010 cls_ = cls or model 1011 1012 for validator in model.__pre_root_validators__: 1013 try: 1014 input_data = validator(cls_, input_data) 1015 except (ValueError, TypeError, AssertionError) as exc: 1016 return {}, set(), ValidationError([ErrorWrapper(exc, loc=ROOT_KEY)], cls_) 1017 1018 for name, field in model.__fields__.items(): 1019 value = input_data.get(field.alias, _missing) 1020 using_name = False 1021 if value is _missing and config.allow_population_by_field_name and field.alt_alias: 1022 value = input_data.get(field.name, _missing) 1023 using_name = True 1024 1025 if value is _missing: 1026 if field.required: 1027 errors.append(ErrorWrapper(MissingError(), loc=field.alias)) 1028 continue 1029 1030 value = field.get_default() 1031 1032 if not config.validate_all and not field.validate_always: 1033 values[name] = value 1034 continue 1035 else: 1036 fields_set.add(name) 1037 if check_extra: 1038 names_used.add(field.name if using_name else field.alias) 1039 1040 v_, errors_ = field.validate(value, values, loc=field.alias, cls=cls_) 1041 if isinstance(errors_, ErrorWrapper): 1042 errors.append(errors_) 1043 elif isinstance(errors_, list): 1044 errors.extend(errors_) 1045 else: 1046 values[name] = v_ 1047 1048 if check_extra: 1049 if isinstance(input_data, GetterDict): 1050 extra = input_data.extra_keys() - names_used 1051 else: 1052 extra = input_data.keys() - names_used 1053 if extra: 1054 fields_set |= extra 1055 if config.extra is Extra.allow: 1056 for f in extra: 1057 values[f] = input_data[f] 1058 else: 1059 for f in sorted(extra): 1060 errors.append(ErrorWrapper(ExtraError(), loc=f)) 1061 1062 for skip_on_failure, validator in model.__post_root_validators__: 1063 if skip_on_failure and errors: 1064 continue 1065 try: 1066 values = validator(cls_, values) 1067 except (ValueError, TypeError, AssertionError) as exc: 1068 errors.append(ErrorWrapper(exc, loc=ROOT_KEY)) 1069 1070 if errors: 1071 return values, fields_set, ValidationError(errors, cls_) 1072 else: 1073 return values, fields_set, None 1074