def cast2dump(cls, result: Any) -> Any: if result is None: return None if isinstance(result, FieldInfo): field_info = result result = (smart_deepcopy(field_info.default) if field_info.default_factory is None else field_info.default_factory()) if result == Ellipsis: raise _InvalidArguments return result if isinstance(result, BaseModel): return cls.cast2dump(result.dict()) if isinstance(result, (int, float, str, bool, type(None))): return result if isinstance(result, Mapping): res_dict = {} for key, value in result.items(): try: res_dict[key] = cls.cast2dump(value) except _InvalidArguments: raise _InvalidArguments( Exception(f'Missing required argument: {key}')) return res_dict if isinstance(result, Iterable): res_list = [] for item in result: res_list.append(cls.cast2dump(item)) return res_list for enc_type, enc_func in ENCODERS_BY_TYPE.items(): if isinstance(result, enc_type): return enc_func(result) return pydantic_encoder(result)
def _remove_trailing_underscore_from_keys(o: dict[str, Any]) -> dict[str, Any]: new_dict = smart_deepcopy(o) for key, value in o.items(): if isinstance(value, dict): value = _remove_trailing_underscore_from_keys(value) new_dict[key.removesuffix("_")] = value return new_dict
def test_smart_deepcopy_empty_collection(empty_collection, mocker): mocker.patch('pydantic.utils.deepcopy', side_effect=RuntimeError) # make sure deepcopy is not used if not isinstance( empty_collection, (tuple, frozenset)): # empty tuple or frozenset are always the same object assert smart_deepcopy(empty_collection) is not empty_collection
def get_default_factory_for_field( field: ModelField) -> Union[NoArgAnyCallable, _Unset]: """ Gets the default factory for a pydantic field. Handles mutable defaults when making the dataclass by using pydantic's smart_deepcopy Returns optionally a NoArgAnyCallable representing a default_factory parameter """ default_factory = field.default_factory default = field.default has_factory = default_factory is not None and not is_unset(default_factory) has_default = default is not None and not is_unset(default) # defining both default and default_factory is not supported if has_factory and has_default: default_factory = cast(NoArgAnyCallable, default_factory) raise BothDefaultAndDefaultFactoryDefinedError( default=default, default_factory=default_factory) # if we have a default_factory, we should return it if has_factory: default_factory = cast(NoArgAnyCallable, default_factory) return default_factory # if we have a default, we should return it if has_default: return lambda: smart_deepcopy(default) # if we don't have default or default_factory, but the field is not required, # we should return a factory that returns None if not field.required: return lambda: None return UNSET
def test_smart_deepcopy_collection(collection, mocker): expected_value = object() mocker.patch('pydantic.utils.deepcopy', return_value=expected_value) assert smart_deepcopy(collection) is expected_value
def test_smart_deepcopy_immutable_non_sequence(obj, mocker): # make sure deepcopy is not used # (other option will be to use obj.copy(), but this will produce error as none of given objects have this method) mocker.patch('pydantic.utils.deepcopy', side_effect=RuntimeError) assert smart_deepcopy(obj) is deepcopy(obj) is obj