def __init__(self, key_type=None, value_type=None, **kw): super(Dict, self).__init__(**kw) # whine if key_type or value_type is not a field if key_type is not None and not IField.providedBy(key_type): raise ValueError("'key_type' must be field instance.") if value_type is not None and not IField.providedBy(value_type): raise ValueError("'value_type' must be field instance.") self.key_type = key_type self.value_type = value_type
async def get_value(self, field: IField, obj: IResource, value: Any) -> Any: try: if value is not None: value = get_adapter(field, IJSONToValue, args=[value, obj]) if asyncio.iscoroutine(value): value = await value field.validate(value) return value except ComponentLookupError: raise ValueDeserializationError(field, value, "Deserializer not found for field")
def __init__(self, value_type=None, unique=False, **kw): super(AbstractCollection, self).__init__(**kw) # whine if value_type is not a field if value_type is not None and not IField.providedBy(value_type): raise ValueError("'value_type' must be field instance.") self.value_type = value_type self.unique = unique
async def __call__(self): result = {'type': self.field_type} for schema in implementedBy(self.field.__class__).flattened(): self.field_attributes.update(getFields(schema)) for attribute_name in sorted(self.field_attributes.keys()): attribute_field = self.field_attributes[attribute_name] if attribute_name in self.filtered_attributes: continue element_name = attribute_field.__name__ attribute_field = attribute_field.bind(self.field) force = (element_name in self.forced_fields) value = attribute_field.get(self.field) # For 'default', 'missing_value' etc, we want to validate against # the imported field type itself, not the field type of the # attribute if element_name in self.field_type_attributes or \ element_name in self.non_validated_field_type_attributes: attribute_field = self.field text = None if isinstance(value, bytes): text = value.decode('utf-8') elif isinstance(value, str): text = value elif IField.providedBy(value): serializer = getMultiAdapter((value, self.field, self.request), ISchemaFieldSerializeToJson) text = await serializer() elif value is not None and (force or value != self.field.missing_value): text = IValueToJson(value) # handle i18n # if isinstance(value, Message): # child.set(ns('domain', I18N_NAMESPACE), value.domain) # if not value.default: # child.set(ns('translate', I18N_NAMESPACE), '') # else: # child.set(ns('translate', I18N_NAMESPACE), child.text) # child.text = converter.toUnicode(value.default) if text: if attribute_name == 'value_type': attribute_name = 'items' result[attribute_name] = text if result['type'] == 'object': if IJSONField.providedBy(self.field): result['properties'] = self.field.json_schema else: schema_serializer = getMultiAdapter( (self.field.schema, self.request), ISchemaSerializeToJson) result['properties'] = await schema_serializer() return result
def get_fields(schema): """Return a dictionary containing all the Fields in a schema. """ from guillotina.schema.interfaces import IField fields = {} for name in schema: attr = schema[name] if IField.providedBy(attr): fields[name] = attr return fields
def __init__(self, value_type=None, unique=False, naive=False, **kw): super(AbstractCollection, self).__init__(**kw) # whine if value_type is not a field if value_type is not None and not IField.providedBy(value_type): raise ValueError("'value_type' must be field instance.") if value_type: value_type.__name__ = self.__name__ self.value_type = value_type self.unique = unique # naive designates if a field's sub type should be validated or not self.naive = naive
def _validate_fields(schema, value, errors=None): if errors is None: errors = [] # Interface can be used as schema property for Object fields that plan to # hold values of any type. # Because Interface does not include any Attribute, it is obviously not # worth looping on its methods and filter them all out. if schema is Interface: return errors # if `value` is part of a cyclic graph, we need to break the cycle to avoid # infinite recursion. Collect validated objects in a thread local dict by # it's python represenation. A previous version was setting a volatile # attribute which didn't work with security proxy if id(value) in VALIDATED_VALUES: return errors VALIDATED_VALUES[id(value)] = True # (If we have gotten here, we know that `value` provides an interface # other than zope.interface.Interface; # iow, we can rely on the fact that it is an instance # that supports attribute assignment.) try: for name in schema.names(all=True): if not IMethod.providedBy(schema[name]): try: attribute = schema[name] if IChoice.providedBy(attribute): # Choice must be bound before validation otherwise # IContextSourceBinder is not iterable in validation bound = attribute.bind(value) bound.validate(getattr(value, name, None)) elif IField.providedBy(attribute): # validate attributes that are fields attribute.validate(getattr(value, name, None)) except ValidationError as error: errors.append(error) except AttributeError as error: # property for the given name is not implemented errors.append(SchemaNotFullyImplemented(error)) finally: del VALIDATED_VALUES[id(value)] return errors
def serialize(self): field = self.get_field() result = {"type": self.field_type} if self.widget is not None: result["widget"] = self.widget # caching the field_attributes here improves performance dramatically if field.__class__ in FIELDS_CACHE: field_attributes = FIELDS_CACHE[field.__class__].copy() else: field_attributes = {} for schema in implementedBy(field.__class__).flattened(): field_attributes.update(get_fields(schema)) FIELDS_CACHE[field.__class__] = field_attributes for attribute_name in sorted(field_attributes.keys()): attribute_field = field_attributes[attribute_name] if attribute_name in self.filtered_attributes: continue element_name = attribute_field.__name__ attribute_field = attribute_field.bind(field) force = element_name in self.forced_fields value = attribute_field.get(field) # For 'default', 'missing_value' etc, we want to validate against # the imported field type itself, not the field type of the # attribute if ( element_name in self.field_type_attributes or element_name in self.non_validated_field_type_attributes ): attribute_field = field text = None if isinstance(value, bytes): text = value.decode("utf-8") elif isinstance(value, str): text = value elif IField.providedBy(value): serializer = get_multi_adapter((value, field, self.request), ISchemaFieldSerializeToJson) text = serializer.serialize() if "properties" in text: text = text["properties"] elif value is not None and (force or value != field.missing_value): text = json_compatible(value) if text: if attribute_name == "value_type": attribute_name = "items" result[attribute_name] = text if result["type"] == "object": if IJSONField.providedBy(field): result.update(field.json_schema) if IDict.providedBy(field): if "properties" not in result: result["properties"] = {} if field.value_type: field_serializer = get_multi_adapter( (field.value_type, self.schema, self.request), ISchemaFieldSerializeToJson ) result["additionalProperties"] = field_serializer.serialize() else: result["additionalProperties"] = True elif IObject.providedBy(field): schema_serializer = get_multi_adapter((field.schema, self.request), ISchemaSerializeToJson) result["properties"] = schema_serializer.serialize() if field.extra_values is not None: result.update(field.extra_values) return result
def getFieldNames(schema): """Return a list of all the Field names in a schema. """ from guillotina.schema.interfaces import IField return [name for name in schema if IField.providedBy(schema[name])]
async def __call__(self): field = self.get_field() result = {'type': self.field_type} # caching the field_attributes here improves performance dramatically if field.__class__ in FIELDS_CACHE: field_attributes = FIELDS_CACHE[field.__class__].copy() else: field_attributes = {} for schema in implementedBy(field.__class__).flattened(): field_attributes.update(get_fields(schema)) FIELDS_CACHE[field.__class__] = field_attributes for attribute_name in sorted(field_attributes.keys()): attribute_field = field_attributes[attribute_name] if attribute_name in self.filtered_attributes: continue element_name = attribute_field.__name__ attribute_field = attribute_field.bind(field) force = (element_name in self.forced_fields) value = attribute_field.get(field) # For 'default', 'missing_value' etc, we want to validate against # the imported field type itself, not the field type of the # attribute if element_name in self.field_type_attributes or \ element_name in self.non_validated_field_type_attributes: attribute_field = field text = None if isinstance(value, bytes): text = value.decode('utf-8') elif isinstance(value, str): text = value elif IField.providedBy(value): serializer = get_multi_adapter((value, field, self.request), ISchemaFieldSerializeToJson) text = await serializer() if 'properties' in text: text = text['properties'] elif value is not None and (force or value != field.missing_value): text = json_compatible(value) if text: if attribute_name == 'value_type': attribute_name = 'items' result[attribute_name] = text if result['type'] == 'object': if IJSONField.providedBy(field): result['properties'] = field.json_schema if IDict.providedBy(field): if field.value_type: field_serializer = get_multi_adapter( (field.value_type, self.schema, self.request), ISchemaFieldSerializeToJson) result['additionalProperties'] = await field_serializer() else: result['additionalProperties'] = True elif IObject.providedBy(field): schema_serializer = get_multi_adapter( (field.schema, self.request), ISchemaSerializeToJson) result['properties'] = await schema_serializer() if field.extra_values is not None: result.update(field.extra_values) return result
def serialize(self): field = self.get_field() result = {'type': self.field_type} # caching the field_attributes here improves performance dramatically if field.__class__ in FIELDS_CACHE: field_attributes = FIELDS_CACHE[field.__class__].copy() else: field_attributes = {} for schema in implementedBy(field.__class__).flattened(): field_attributes.update(get_fields(schema)) FIELDS_CACHE[field.__class__] = field_attributes for attribute_name in sorted(field_attributes.keys()): attribute_field = field_attributes[attribute_name] if attribute_name in self.filtered_attributes: continue element_name = attribute_field.__name__ attribute_field = attribute_field.bind(field) force = (element_name in self.forced_fields) value = attribute_field.get(field) # For 'default', 'missing_value' etc, we want to validate against # the imported field type itself, not the field type of the # attribute if element_name in self.field_type_attributes or \ element_name in self.non_validated_field_type_attributes: attribute_field = field text = None if isinstance(value, bytes): text = value.decode('utf-8') elif isinstance(value, str): text = value elif IField.providedBy(value): serializer = get_multi_adapter( (value, field, self.request), ISchemaFieldSerializeToJson) text = serializer.serialize() if 'properties' in text: text = text['properties'] elif value is not None and (force or value != field.missing_value): text = json_compatible(value) if text: if attribute_name == 'value_type': attribute_name = 'items' result[attribute_name] = text if result['type'] == 'object': if IJSONField.providedBy(field): result.update(field.json_schema) if IDict.providedBy(field): if field.value_type: field_serializer = get_multi_adapter( (field.value_type, self.schema, self.request), ISchemaFieldSerializeToJson) result['additionalProperties'] = field_serializer.serialize() else: result['additionalProperties'] = True elif IObject.providedBy(field): schema_serializer = get_multi_adapter((field.schema, self.request), ISchemaSerializeToJson) result['properties'] = schema_serializer.serialize() if field.extra_values is not None: result.update(field.extra_values) return result