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 resolve(__self, __info, **kwargs): values = {} errors: Dict[str, ValidationError] = {} for alias, param_name, deserializer, opt_param, required in parameters: if alias in kwargs: # It is possible for the parameter to be non-optional in Python # type hints but optional in the generated schema. In this case # we should ignore it. # See: https://github.com/wyfo/apischema/pull/130#issuecomment-845497392 if not opt_param and kwargs[alias] is None: assert not required continue try: values[param_name] = deserializer(kwargs[alias]) except ValidationError as err: errors[aliaser(param_name)] = err elif opt_param and required: values[param_name] = None if errors: raise ValueError(ValidationError(children=errors).errors) if info_parameter: values[info_parameter] = __info try: return serialize_result(func(__self, **values)) except Exception as error: if error_handler is None: raise assert serialize_error is not None return serialize_error(error_handler(error, __self, __info, **kwargs))
def method(data: Any) -> Any: try: result = values[primitive_values.index(data)] except ValueError: raise ValidationError([f"not one of {primitive_values}"]) deserialize_any(data) # for validation return result
def method(data: Any) -> Any: try: return converter( conv_deserializer(data)) # type: ignore except (ValidationError, AssertionError): raise except Exception as err: raise ValidationError([str(err)])
def no_coercion(expected: Type[T], data: Any) -> T: if not isinstance(data, expected): if expected is float and isinstance(data, int): return float(data) # type: ignore msg = (f"expected type {JsonType.from_type(expected)}," f" found {JsonType.from_type(type(data))}") raise ValidationError([msg]) return data
def method(data: Any) -> Any: if constraints is not None: cls = type(data) if cls in constraints.errors_by_type: errors = constraints.errors_by_type[cls](data) if errors: raise ValidationError(errors) return data
def method(data: Any) -> Any: if not isinstance(data, cls): if cls == float and isinstance(data, int): data = float(data) else: raise bad_type(data, cls) if data is not None: errors = constraint_errors(data) if errors: raise ValidationError(errors) return data
def method(data: Any) -> Any: if not isinstance(data, dict): raise bad_type(data, dict) items = {} item_errors: Dict[ErrorKey, ValidationError] = {} for key, value in data.items(): assert isinstance(key, str) try: items[deserialize_key(key)] = deserialize_value(value) except ValidationError as err: item_errors[key] = err errors = constraint_errors(data) if constraint_errors else () if item_errors or errors: raise ValidationError(errors, item_errors) return items if cls is DICT_TYPE else MAPPING_TYPES[cls](items)
def method(data: Any) -> Any: if not isinstance(data, list): raise bad_type(data, list) elts: List[Any] = [] elt_errors: Dict[ErrorKey, ValidationError] = {} for i, (deserialize_elt, elt) in enumerate(zip(elt_deserializers, data)): try: elts.append(deserialize_elt(elt)) except ValidationError as err: elt_errors[i] = err errors = constraint_errors(data) if constraint_errors else () if elt_errors or errors: raise ValidationError(errors, elt_errors) return tuple(elts)
def method(data: Any) -> Any: if not isinstance(data, list): raise bad_type(data, list) elts = [] elt_errors: Dict[ErrorKey, ValidationError] = {} for i, elt in enumerate(data): try: elts.append(deserialize_value(elt)) except ValidationError as err: elt_errors[i] = err errors = constraint_errors(data) if constraint_errors else () if elt_errors or errors: raise ValidationError(errors, elt_errors) return elts if cls is LIST_TYPE else COLLECTION_TYPES[cls]( elts)
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)])
def resolve(self, info, **kwargs): errors: Dict[str, ValidationError] = {} for arg_name, arg_type in arg_types: if arg_name in kwargs: try: kwargs[arg_name] = deserialize(arg_type, kwargs[arg_name]) except ValidationError as err: errors[aliaser(arg_name)] = err if errors: raise TypeError(serialize(ValidationError(children=errors))) if info_param: kwargs[info_param] = info try: return serialize_result(func(self, **kwargs)) except Exception: if error_as_null: return None else: raise
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 bad_type(data: Any, expected: type) -> ValidationError: msg = (f"expected type {JsonType.from_type(expected)}," f" found {JsonType.from_type(data.__class__)}") return ValidationError([msg])
def validate(self, data: T) -> T: errors = self.errors(data) if errors: raise ValidationError(errors) return data
def coercion_error(cls: Type, data) -> ValidationError: msg = (f"cannot coerce {JsonType.from_type(cls)}" f" from {JsonType.from_type(type(data))}") return ValidationError([msg])
deprecate_kwargs, get_origin_or_type, identity, literal_values, opt_or, ) from apischema.validation import get_validators from apischema.validation.errors import ErrorKey, ValidationError, merge_errors from apischema.validation.mock import ValidatorMock from apischema.validation.validators import Validator, validate from apischema.visitor import Unsupported DICT_TYPE = get_origin(Dict[Any, Any]) LIST_TYPE = get_origin(List[Any]) MISSING_PROPERTY = ValidationError(["missing property"]) UNEXPECTED_PROPERTY = ValidationError(["unexpected property"]) NOT_NONE = object() INIT_VARS_ATTR = f"{PREFIX}_init_vars" T = TypeVar("T") DeserializationMethod = Callable[[Any], T] @dataclass(frozen=True) class DeserializationMethodFactory: factory: Callable[[Optional[Constraints], Sequence[Validator]], DeserializationMethod]
def validate(__obj, **kwargs): try: wrapped_field(__obj, **kwargs) except ValidationError as err: raise ValidationError(children={FieldPath(field): err})