class IntegerUnmarshaller(PrimitiveTypeUnmarshaller): FORMATTERS = { SchemaFormat.NONE: Formatter.from_callables( partial(is_integer, None), int), SchemaFormat.INT32: Formatter.from_callables( partial(oas30_format_checker.check, format='int32'), int), SchemaFormat.INT64: Formatter.from_callables( partial(oas30_format_checker.check, format='int64'), int), }
class NumberUnmarshaller(PrimitiveTypeUnmarshaller): FORMATTERS = { SchemaFormat.NONE: Formatter.from_callables( partial(is_number, None), format_number), SchemaFormat.FLOAT: Formatter.from_callables( partial(oas30_format_checker.check, format='float'), float), SchemaFormat.DOUBLE: Formatter.from_callables( partial(oas30_format_checker.check, format='double'), float), }
class NumberUnmarshaller(PrimitiveTypeUnmarshaller): FORMATTERS = { None: Formatter.from_callables(partial(is_number, None), format_number), "float": Formatter.from_callables( partial(oas30_format_checker.check, format="float"), float), "double": Formatter.from_callables( partial(oas30_format_checker.check, format="double"), float), }
class IntegerUnmarshaller(PrimitiveTypeUnmarshaller): FORMATTERS = { None: Formatter.from_callables(partial(is_integer, None), int), "int32": Formatter.from_callables( partial(oas30_format_checker.check, format="int32"), int), "int64": Formatter.from_callables( partial(oas30_format_checker.check, format="int64"), int), }
class StringUnmarshaller(PrimitiveTypeUnmarshaller): FORMATTERS = { None: Formatter.from_callables(partial(is_string, None), str), "password": Formatter.from_callables( partial(oas30_format_checker.check, format="password"), str), "date": Formatter.from_callables( partial(oas30_format_checker.check, format="date"), format_date), "date-time": Formatter.from_callables( partial(oas30_format_checker.check, format="date-time"), parse_datetime, ), "binary": Formatter.from_callables( partial(oas30_format_checker.check, format="binary"), bytes), "uuid": Formatter.from_callables( partial(oas30_format_checker.check, format="uuid"), format_uuid), "byte": Formatter.from_callables( partial(oas30_format_checker.check, format="byte"), format_byte), }
class StringUnmarshaller(PrimitiveTypeUnmarshaller): FORMATTERS = { SchemaFormat.NONE: Formatter.from_callables(partial(is_string, None), text_type), SchemaFormat.PASSWORD: Formatter.from_callables( partial(oas30_format_checker.check, format='password'), text_type), SchemaFormat.DATE: Formatter.from_callables( partial(oas30_format_checker.check, format='date'), format_date), SchemaFormat.DATETIME: Formatter.from_callables( partial(oas30_format_checker.check, format='date-time'), parse_datetime), SchemaFormat.BINARY: Formatter.from_callables( partial(oas30_format_checker.check, format='binary'), binary_type), SchemaFormat.UUID: Formatter.from_callables( partial(oas30_format_checker.check, format='uuid'), format_uuid), SchemaFormat.BYTE: Formatter.from_callables( partial(oas30_format_checker.check, format='byte'), format_byte), }
class StringUnmarshaller(PrimitiveTypeUnmarshaller): FORMATTERS = { None: Formatter.from_callables(partial(is_string, None), text_type), 'password': Formatter.from_callables( partial(oas30_format_checker.check, format='password'), text_type), 'date': Formatter.from_callables( partial(oas30_format_checker.check, format='date'), format_date), 'date-time': Formatter.from_callables( partial(oas30_format_checker.check, format='date-time'), parse_datetime), 'binary': Formatter.from_callables( partial(oas30_format_checker.check, format='binary'), binary_type), 'uuid': Formatter.from_callables( partial(oas30_format_checker.check, format='uuid'), format_uuid), 'byte': Formatter.from_callables( partial(oas30_format_checker.check, format='byte'), format_byte), }
class ArrayUnmarshaller(ComplexUnmarshaller): FORMATTERS = { None: Formatter.from_callables(partial(is_array, None), list), } @property def items_unmarshaller(self): return self.unmarshallers_factory.create(self.schema / "items") def __call__(self, value): value = super().__call__(value) if value is None and self.schema.getkey("nullable", False): return None return list(map(self.items_unmarshaller, value))
class ArrayUnmarshaller(ComplexUnmarshaller): FORMATTERS = { SchemaFormat.NONE: Formatter.from_callables(partial(is_array, None), list), } @property def items_unmarshaller(self): return self.unmarshallers_factory.create(self.schema.items) def __call__(self, value=NoValue): value = super(ArrayUnmarshaller, self).__call__(value) return list(map(self.items_unmarshaller, value))
class AnyUnmarshaller(ComplexUnmarshaller): FORMATTERS = { SchemaFormat.NONE: Formatter(), } SCHEMA_TYPES_ORDER = [ SchemaType.OBJECT, SchemaType.ARRAY, SchemaType.BOOLEAN, SchemaType.INTEGER, SchemaType.NUMBER, SchemaType.STRING, ] def __call__(self, value=NoValue): one_of_schema = self._get_one_of_schema(value) if one_of_schema: return self.unmarshallers_factory.create(one_of_schema)(value) for schema_type in self.SCHEMA_TYPES_ORDER: unmarshaller = self.unmarshallers_factory.create( self.schema, type_override=schema_type) # validate with validator of formatter (usualy type validator) try: unmarshaller._formatter_validate(value) except ValidateError: continue else: return unmarshaller(value) log.warning("failed to unmarshal any type") return value def _get_one_of_schema(self, value): if not self.schema.one_of: return for subschema in self.schema.one_of: unmarshaller = self.unmarshallers_factory.create(subschema) try: unmarshaller.validate(value) except ValidateError: continue else: return subschema
class BaseSchemaUnmarshaller: FORMATTERS = { None: Formatter(), } def __init__(self, schema): self.schema = schema def __call__(self, value): if value is None: return self.validate(value) return self.unmarshal(value) def validate(self, value): raise NotImplementedError def unmarshal(self, value): raise NotImplementedError
class ObjectUnmarshaller(ComplexUnmarshaller): FORMATTERS = { None: Formatter.from_callables(partial(is_object, None), dict), } @property def model_factory(self): return ModelFactory() def unmarshal(self, value): try: value = self.formatter.unmarshal(value) except ValueError as exc: raise InvalidSchemaFormatValue(value, self.schema.format, exc) else: return self._unmarshal_object(value) def _unmarshal_object(self, value): if "oneOf" in self.schema: properties = None for one_of_schema in self.schema / "oneOf": try: unmarshalled = self._unmarshal_properties( value, one_of_schema) except (UnmarshalError, ValueError): pass else: if properties is not None: log.warning("multiple valid oneOf schemas found") continue properties = unmarshalled if properties is None: log.warning("valid oneOf schema not found") else: properties = self._unmarshal_properties(value) if "x-model" in self.schema: name = self.schema["x-model"] return self.model_factory.create(properties, name=name) return properties def _unmarshal_properties(self, value, one_of_schema=None): all_props = get_all_properties(self.schema) all_props_names = get_all_properties_names(self.schema) if one_of_schema is not None: all_props.update(get_all_properties(one_of_schema)) all_props_names |= get_all_properties_names(one_of_schema) value_props_names = list(value.keys()) extra_props = set(value_props_names) - set(all_props_names) properties = {} additional_properties = self.schema.getkey("additionalProperties", True) if isinstance(additional_properties, dict): additional_prop_schema = self.schema / "additionalProperties" for prop_name in extra_props: prop_value = value[prop_name] properties[prop_name] = self.unmarshallers_factory.create( additional_prop_schema)(prop_value) elif additional_properties is True: for prop_name in extra_props: prop_value = value[prop_name] properties[prop_name] = prop_value for prop_name, prop in list(all_props.items()): read_only = prop.getkey("readOnly", False) if self.context == UnmarshalContext.REQUEST and read_only: continue write_only = prop.getkey("writeOnly", False) if self.context == UnmarshalContext.RESPONSE and write_only: continue try: prop_value = value[prop_name] except KeyError: if "default" not in prop: continue prop_value = prop["default"] properties[prop_name] = self.unmarshallers_factory.create(prop)( prop_value) return properties
class BooleanUnmarshaller(PrimitiveTypeUnmarshaller): FORMATTERS = { None: Formatter.from_callables(partial(is_bool, None), forcebool), }
class ObjectUnmarshaller(ComplexUnmarshaller): FORMATTERS = { SchemaFormat.NONE: Formatter.from_callables(partial(is_object, None), dict), } @property def model_factory(self): return ModelFactory() def unmarshal(self, value): try: value = self.formatter.unmarshal(value) except ValueError as exc: raise InvalidSchemaFormatValue(value, self.schema.format, exc) else: return self._unmarshal_object(value) def _unmarshal_object(self, value=NoValue): if self.schema.one_of: properties = None for one_of_schema in self.schema.one_of: try: unmarshalled = self._unmarshal_properties( value, one_of_schema) except (UnmarshalError, ValueError): pass else: if properties is not None: log.warning("multiple valid oneOf schemas found") continue properties = unmarshalled if properties is None: log.warning("valid oneOf schema not found") else: properties = self._unmarshal_properties(value) if 'x-model' in self.schema.extensions: extension = self.schema.extensions['x-model'] return self.model_factory.create(properties, name=extension.value) return properties def _unmarshal_properties(self, value=NoValue, one_of_schema=None): all_props = self.schema.get_all_properties() all_props_names = self.schema.get_all_properties_names() if one_of_schema is not None: all_props.update(one_of_schema.get_all_properties()) all_props_names |= one_of_schema.\ get_all_properties_names() value_props_names = value.keys() extra_props = set(value_props_names) - set(all_props_names) properties = {} if isinstance(self.schema.additional_properties, Schema): for prop_name in extra_props: prop_value = value[prop_name] properties[prop_name] = self.unmarshallers_factory.create( self.schema.additional_properties)(prop_value) elif self.schema.additional_properties is True: for prop_name in extra_props: prop_value = value[prop_name] properties[prop_name] = prop_value for prop_name, prop in iteritems(all_props): if self.context == UnmarshalContext.REQUEST and prop.read_only: continue if self.context == UnmarshalContext.RESPONSE and prop.write_only: continue try: prop_value = value[prop_name] except KeyError: if prop.default is NoValue: continue prop_value = prop.default properties[prop_name] = self.unmarshallers_factory.create(prop)( prop_value) return properties
if not isinstance(value, str): return False if not value: return True return self.regex.match(value) CUSTOM_FORMATTERS = { 'uri': Formatter.from_callables( RegexValidator( r'^(?:http|ftp)s?://' r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[A-Z]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' # noqa: E501 r'localhost|' r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' r'(?::\d+)?' r'(?:/?|[/?]\S+)$', ), str, ), 'iso8601': Formatter.from_callables( RegexValidator(r'^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d\.\d{6}$'), str, ), 'email': Formatter.from_callables( RegexValidator(r'[^@]+@[^@]+\.[^@]+'), str, ), }
class AnyUnmarshaller(ComplexUnmarshaller): FORMATTERS = { None: Formatter(), } SCHEMA_TYPES_ORDER = [ 'object', 'array', 'boolean', 'integer', 'number', 'string', ] def unmarshal(self, value=NoValue): one_of_schema = self._get_one_of_schema(value) if one_of_schema: return self.unmarshallers_factory.create(one_of_schema)(value) all_of_schema = self._get_all_of_schema(value) if all_of_schema: return self.unmarshallers_factory.create(all_of_schema)(value) for schema_type in self.SCHEMA_TYPES_ORDER: unmarshaller = self.unmarshallers_factory.create( self.schema, type_override=schema_type) # validate with validator of formatter (usualy type validator) try: unmarshaller._formatter_validate(value) except ValidateError: continue else: return unmarshaller(value) log.warning("failed to unmarshal any type") return value def _get_one_of_schema(self, value): if 'oneOf' not in self.schema: return one_of_schemas = self.schema / 'oneOf' for subschema in one_of_schemas: unmarshaller = self.unmarshallers_factory.create(subschema) try: unmarshaller.validate(value) except ValidateError: continue else: return subschema def _get_all_of_schema(self, value): if 'allOf' not in self.schema: return all_of_schemas = self.schema / 'allOf' for subschema in all_of_schemas: if 'type' not in subschema: continue unmarshaller = self.unmarshallers_factory.create(subschema) try: unmarshaller.validate(value) except ValidateError: continue else: return subschema