def method(data: Any) -> Any: if not isinstance(data, dict): raise bad_type(data, dict) values: Dict[str, Any] = {} aliases: List[str] = [] errors = list( constraint_errors(data)) if constraint_errors else [] field_errors: Dict[ErrorKey, ValidationError] = OrderedDict() for ( name, alias, field_method, required, fall_back_on_default, ) in normal_fields: if alias in data: aliases.append(alias) try: values[name] = field_method(data[alias]) except ValidationError as err: if not fall_back_on_default: field_errors[alias] = err elif not required: pass elif required is True: field_errors[alias] = MISSING_PROPERTY else: assert isinstance(required, AbstractSet) requiring = required & data.keys() if requiring: msg = f"missing property (required by {sorted(requiring)})" field_errors[alias] = ValidationError([msg]) if has_aggregate_field: for ( name, flattened_alias, field_method, fall_back_on_default, ) in flattened_fields: flattened = { alias: data[alias] for alias in flattened_alias if alias in data } aliases.extend(flattened) try: values[name] = field_method(flattened) except ValidationError as err: if not fall_back_on_default: errors.extend(err.messages) field_errors.update(err.children) if len(data) != len(aliases): remain = data.keys() - set(aliases) else: remain = set() for ( name, pattern, field_method, fall_back_on_default, ) in pattern_fields: matched = { key: data[key] for key in remain if pattern.match(key) } remain -= matched.keys() try: values[name] = field_method(matched) except ValidationError as err: if not fall_back_on_default: errors.extend(err.messages) field_errors.update(err.children) if additional_field is not None: name, field_method, fall_back_on_default = additional_field additional = {key: data[key] for key in remain} try: values[name] = field_method(additional) except ValidationError as err: if not fall_back_on_default: errors.extend(err.messages) field_errors.update(err.children) elif remain and not additional_properties: for key in remain: field_errors[key] = UNEXPECTED_PROPERTY elif len(data) != len(aliases) and not additional_properties: for key in data.keys() - set(aliases): field_errors[key] = UNEXPECTED_PROPERTY validators2: Sequence[Validator] if validators: init: Dict[str, Any] = {} for name, default_factory in init_defaults: if name in values: init[name] = values[name] elif name not in field_errors: assert default_factory is not None init[name] = default_factory() # Don't keep validators when all dependencies are default validators2 = [ v for v in validators if v.dependencies & values.keys() ] if field_errors or errors: error = ValidationError(errors, field_errors) invalid_fields = field_errors.keys( ) | post_init_modified validators2 = [ v for v in validators2 if not v.dependencies & invalid_fields ] try: validate( ValidatorMock(cls, values), validators2, init, aliaser=aliaser, ) except ValidationError as err: error = merge_errors(error, err) raise error elif field_errors or errors: raise ValidationError(errors, field_errors) else: validators2, init = ( ), ... # type: ignore # only for linter try: res = cls(**values) except (AssertionError, ValidationError): raise except TypeError as err: if str(err).startswith("__init__() got"): raise Unsupported(cls) else: raise ValidationError([str(err)]) except Exception as err: raise ValidationError([str(err)]) if validators2: validate(res, validators2, init, aliaser=aliaser) return res
def validate( obj: T, validators: Iterable[Validator] = None, kwargs: Mapping[str, Any] = None, *, aliaser: Aliaser = lambda s: s, ) -> T: if validators is None: validators = get_validators(type(obj)) error: Optional[ValidationError] = None validators = iter(validators) for validator in validators: try: if not kwargs: validator.validate(obj) elif validator.params == kwargs.keys(): validator.validate(obj, **kwargs) else: if any(k not in kwargs for k in validator.params): raise RuntimeError( f"Missing parameters {kwargs.keys() - validator.params}" f" for validator {validator.func}") validator.validate(obj, **{k: kwargs[k] for k in validator.params}) except ValidationError as e: err = apply_aliaser(e, aliaser) except NonTrivialDependency as exc: exc.validator = validator raise except AssertionError: raise except Exception as e: err = ValidationError([str(e)]) else: continue if validator.field is not None: alias = getattr(get_alias(validator.owner), get_field_name(validator.field)) err = ValidationError(children={aliaser(alias): err}) error = merge_errors(error, err) if validator.discard: try: discarded = set(map(get_field_name, validator.discard)) next_validators = (v for v in validators if not discarded & v.dependencies) validate(obj, next_validators, kwargs, aliaser=aliaser) except ValidationError as err: error = merge_errors(error, err) if error is not None: raise error return obj
def method(data: Any) -> Any: # Optional optimization if data is none_check: return None error: Optional[ValidationError] = None for deserialize_alt in alt_deserializers: try: return deserialize_alt(data) except ValidationError as err: error = merge_errors(error, err) if none_check is None: error = merge_errors(error, bad_type(data, NoneType)) if error is None: # empty union return data else: raise error
def validate(__obj: T, __validators: Iterable[Validator] = None, **kwargs) -> T: if __validators is None: __validators = get_validators(__obj) if not __validators: return __obj error: Optional[ValidationError] = None __validators = iter(__validators) while True: for validator in __validators: try: if kwargs and validator.params != kwargs.keys(): assert all(k in kwargs for k in validator.params) validator.validate( __obj, **{k: kwargs[k] for k in validator.params} ) else: validator.validate(__obj, **kwargs) except ValidationError as err: error = merge_errors(error, err) except Discard as err: error = merge_errors(error, err.error) discarded = {f.name for f in err.fields} __validators = iter( v for v in __validators if not discarded & v.dependencies ) break except NonTrivialDependency as exc: exc.validator = validator raise except AssertionError: raise except Exception as err: error = merge_errors(error, ValidationError([str(err)])) else: break if error is not None: raise error return __obj
def method(data: Any) -> Any: error: Optional[ValidationError] = None for deserialize_conv, converter in conv_deserializers: try: value = deserialize_conv(data) break except ValidationError as err: error = merge_errors(error, err) else: assert error is not None raise error try: return converter(value) # type: ignore except (ValidationError, AssertionError): raise except Exception as err: raise ValidationError([str(err)])