def oneOf(validator, oneOf, instance, schema, errors): valids = [] all_errors = [] for index, subschema in enumerate(oneOf): erroff = len(errors) ret = validator._descend( instance, subschema, errors, schema_path=index) if len(errors) == erroff: valids.append((ret, subschema)) else: all_errors.extend(errors[erroff:]) del errors[erroff:] if len(valids) == 1: return valids[0][0][0], oneOf if not valids: errors.append(ValidationError( '{} is not valid under any of the given schemas'.format(instance), context=all_errors, )) elif len(valids) > 1: errors.append(ValidationError( '{} is valid under each of {}'.format( instance, ', '.join(repr(schema) for _, schema in valids))))
def additionalProperties(validator, aP, instance, schema, errors): if not validator.is_type(instance, 'object', schema): return extras = set() properties = schema.get("properties", {}) patterns = schema.get("patternProperties", {}) if patterns and isinstance(patterns, dict): patterns = validator._get_regex('|'.join(patterns)) else: patterns = None for name in instance: if name not in properties: if patterns and patterns.search(name): continue extras.add(name) if validator.is_type(aP, 'object', schema): new_instance = dict(instance) for extra in extras: new_instance[extra], _ = validator._descend( instance[extra], aP, errors, path=extra) return new_instance, aP elif not aP and extras: if patterns: patterns = sorted(schema['patternProperties']) errors.append(ValidationError( '{} do not match any of the regexes: {}'.format( ', '.join(map(repr, sorted(extras))), ', '.join(map(repr, patterns))))) else: errors.append(ValidationError( 'Additional properties are not allowed ' '({} were unexpected)'.format(extras)))
def required(validator, required, instance, schema, errors): if not validator.is_type(instance, 'object', schema): return for property in required: if property not in instance: errors.append(ValidationError( '{} is a required property'.format(property)))
def not_(validator, not_, instance, schema, errors): tmp_errors = [] validator._descend(instance, not_, tmp_errors) if len(tmp_errors) != 0: return errors.append(ValidationError( '{} is not allowed for {}'.format(not_, instance)))
def format(validator, format, instance, schema, errors): if validator.format_checker is not None: try: instance = validator.format_checker.check(instance, format) except Exception as e: errors.append(ValidationError(str(e), cause=e.__cause__)) return instance, format
def multipleOf(validator, mO, instance, schema, errors): if not validator.is_type(instance, 'number', schema): return if isinstance(mO, float): quotient = instance / mO failed = int(quotient) != quotient else: failed = instance % mO if failed: errors.append(ValidationError( '{} is not a multiple of {}'.format(instance, mO)))
def minimum(validator, minimum, instance, schema, errors): if not validator.is_type(instance, 'number', schema): return if schema.get('exclusiveMinimum', False): failed = instance <= minimum cmp = 'less than or equal to' else: failed = instance < minimum cmp = 'less than' if failed: errors.append(ValidationError( '{} is {} the minimum of {}'.format(instance, cmp, minimum)))
def _validate_and_parse(Validator, resolver, request, path_matches, op_obj, fill_by_default): params, queries = {}, {} if request.query_string: try: queries = parse_qs(request.query_string, keep_blank_values=True, strict_parsing=True) except Exception: raise HTTPBadRequest('cannot parse query string') for param_obj in op_obj.get('parameters', []): params.update( _validate_and_parse_param(Validator, request, param_obj, path_matches, queries, fill_by_default)) body = None reqbody = op_obj.get('requestBody') if reqbody: if '$ref' in reqbody: _, reqbody = resolver.resolve(reqbody['$ref']) required = reqbody.get('required', False) body = request.body if required and not body: raise ValidationErrors(ValidationError('body is required')) accept_types = set(reqbody.get('content', {}).keys()) if (body and not _validate_media_types(request.content_type, accept_types)): raise HTTPNotAcceptable media_type_obj = reqbody.get('content', {}).get(MIME_JSON) if media_type_obj is not None and body: try: body = json.loads(body.decode('utf8')) except Exception: raise ValidationErrors(ValidationError('invalid json')) json_schema = media_type_obj.get('schema') if json_schema: body = _validate(Validator, json_schema, body) return params, body
def additionalItems(validator, aI, instance, schema, errors): if (not validator.is_type(instance, 'array', schema) or validator.is_type(schema.get('items', {}), 'object', schema)): return items_array = schema.get('items', []) if validator.is_type(aI, 'object', schema): new_instance = list(instance) for index, item in enumerate( instance[len(items_array):], start=len(items_array)): new_instance[index] = validator._descend( item, aI, errors, path=index) elif not aI and len(instance) > len(items_array): errors.append(ValidationError( 'Additional items are not allowed ({} were unexpected)'.format( ', '.join([ str(x) for x in instance[len(items_array):]]))))
def validator_tween(request): route_info = route_mapper(request) route = route_info.get('route', None) if not route: # pragma: no cover return handler(request) op_obj = get_operation_object(route.path, request.method) if not op_obj: # pragma: no cover return handler(request) _check_security(default_security, request, op_obj) params, body = _validate_and_parse(Validator, resolver, request, route_info.get('match', {}), op_obj, fill_default) def oas3_data(_): return params def oas3_body(_): return body request.set_property(oas3_data) request.set_property(oas3_body) response = handler(request) if not validate_response: return response try: responses_obj = op_obj['responses'] res_obj = responses_obj.get(str(response.status_code), responses_obj.get('default')) if res_obj is None: raise ValidationErrors( ValidationError('invalid response status code')) content_prop = res_obj.get('content') if response.content_type == MIME_JSON: res_schema = content_prop.get(MIME_JSON, {}).get('schema') if res_schema: res_json = json.loads(response.body.decode('utf8')) if response_reviver: res_json = apply_reviver(res_json, response_reviver) _validate(Validator, res_schema, res_json) except Exception as e: raise ResponseValidationError(response, e) return response
def anyOf(validator, anyOf, instance, schema, errors): valids, all_errors = [], [] for index, subschema in enumerate(anyOf): erroff = len(errors) ret, _ = validator._descend( instance, subschema, errors, schema_path=index) if len(errors) == erroff: valids.append(ret) else: all_errors.extend(errors[erroff:]) del errors[erroff:] if len(valids) > 0: return _utils.merge_instances(valids), anyOf errors.append(ValidationError( '{} is not valid under any of the given schemas'.format(instance), context=all_errors, ))
def maxLength(validator, mL, instance, schema, errors): if (validator.is_type(instance, 'string', schema) and len(instance) > mL): errors.append(ValidationError('{} is too long'.format(instance,)))
def pattern(validator, pattern, instance, schema, errors): if (validator.is_type(instance, 'string', schema) and not validator._get_regex(pattern).search(instance)): errors.append(ValidationError( '{} does not match {}'.format(instance, pattern)))
def type(validator, types, instance, schema, errors): types = _utils.ensure_list(types) if not any(validator.is_type(instance, type, schema) for type in types): errors.append(ValidationError('{} is not of type {}'.format( instance, ', '.join(types))))
def uniqueItems(validator, uI, instance, schema, errors): if (uI and validator.is_type(instance, 'array', schema) and not _utils.is_uniq(instance)): errors.append(ValidationError( '{} has non-unique elements'.format(instance)))
def enum(validator, enum, instance, schema, errors): if instance not in enum: errors.append(ValidationError( '{} is not one of {}'.format(instance, enum)))
def maxProperties(validator, mP, instance, schema, errors): if validator.is_type(instance, 'object', schema) and len(instance) > mP: errors.append(ValidationError( '{} has too many properties'.format(instance)))
def minProperties(validator, mP, instance, schema, errors): if validator.is_type(instance, 'object', schema) and len(instance) < mP: errors.append(ValidationError( '{} does not have enough properties'.format(instance)))
def _validate_and_parse_param(Validator, request, param_obj, path_matches, queries, fill_by_default): if param_obj.get('allowEmptyValue', False): raise NotImplementedError # pragma: no cover in_, name, schema, value = (param_obj['in'], param_obj['name'], param_obj.get('schema'), None) style = param_obj.get('style', 'form' if in_ in ('query', 'cookie') else 'simple') explode = param_obj.get('explode', True if style == 'form' else False) type_tries = set() if not schema: typ = 'object' elif 'type' in schema: typ = schema['type'] else: # QUICKHACK(kazuki): プリミティブ型のoneOf/anyOfのみ許容する def _check_subschemas(s): st = s.get('type') if st is not None: if st in ('integer', 'number', 'string', 'boolean'): type_tries.add(st) return st raise NotImplementedError ss_list = s.get('oneOf', s.get('anyOf')) if not ss_list: raise NotImplementedError for ss in ss_list: t = _check_subschemas(ss) return t typ = _check_subschemas(schema) if typ is None: raise NotImplementedError if style in ('matrix', 'label', 'spaceDelimited', 'pipeDelimited'): raise NotImplementedError # pragma: no cover if in_ == 'path': value = path_matches[name] # always successful elif in_ == 'query': if style == 'form' and typ == 'object' and explode: raise NotImplementedError # pragma: no cover if style == 'deepObject': value = {} for k, v in queries.items(): if k.startswith(name + '[') and k[-1] == ']': value[k[len(name) + 1:-1]] = v[0] if not value: value = None else: if name in queries: value = queries[name] if not (style == 'form' and explode and typ == 'array'): value = value[0] elif schema and fill_by_default and 'default' in schema: return {name: schema['default']} elif in_ == 'header' and name in request.headers: value = request.headers[name] elif in_ == 'cookie': # pragma: no cover raise NotImplementedError if param_obj.get('required', False) and value is None: raise ValidationErrors( ValidationError( 'required parameter "{}" is not found in {}'.format(name, in_))) if value is None: return {} if not type_tries: type_tries.add(typ) errors = [] for typ in type_tries: if not isinstance(value, dict): try: value = _convert_style(style, explode, typ, value) except Exception as e: errors.append( StyleError('invalid style of "{}": {}'.format(name, e))) continue if schema: try: value = _convert_type(schema, value, default_type=typ) except Exception as e: errors.append( ValueError('invalid value of "{}": {}'.format(name, e))) continue try: value = _validate(Validator, schema, value) except Exception as e: errors.append(e) continue return {name: value} raise ValidationErrors(errors)
def maxItems(validator, maxItems, instance, schema, errors): if (validator.is_type(instance, 'array', schema) and len(instance) > maxItems): errors.append(ValidationError('{} is too long'.format(instance,)))