def __call__(self, context, value): if not isinstance(value, list): raise ValueDeserializationError( self.field, value, f'Invalid type patch data, must be list of updates') existing = getattr(context, self.field.__name__, None) if existing is None: existing = self.field.missing_value or {} for item in value: if 'key' not in item or 'value' not in item: raise ValueDeserializationError(self.field, value, 'Not valid patch value') existing_item = existing.get(item['key']) new_value = self.get_value(item['value'], existing_item) if self.field.key_type: self.field.key_type.validate(item['key']) if self.field.value_type: self.field.value_type.validate(new_value) existing[item['key']] = new_value return existing
async def __call__(self, field_context, context, value): if not isinstance(value, list): raise ValueDeserializationError( self.field, value, f"Invalid type patch data, must be list of updates") if self.field.max_ops and len(value) > self.field.max_ops: raise ValueDeserializationError( self.field, value, f"Exceeded max allowed operations for field: {self.field.max_ops}" ) existing = self.get_existing_value(field_context) for item in value: if "key" not in item or "value" not in item: raise ValueDeserializationError(self.field, value, "Not valid patch value") if self.field.key_type: self.field.key_type.validate(item["key"]) existing_item = await existing.get(context, item["key"]) new_value = self.get_value(item["value"], existing_item) if self.field.value_type: self.field.value_type.validate(new_value) await existing.assign(context, item["key"], new_value)
def __call__(self, context, value): if not isinstance(value, list): raise ValueDeserializationError( self.field, value, f"Invalid type patch data, must be list of updates") existing = getattr(context, self.field.__name__, None) if existing is None: existing = self.field.missing_value or {} if self.field.max_ops and len(value) > self.field.max_ops: raise ValueDeserializationError( self.field, value, f"Exceeded max allowed operations for field: {self.field.max_ops}" ) for item in value: if "key" not in item or "value" not in item: raise ValueDeserializationError(self.field, value, "Not valid patch value") existing_item = existing.get(item["key"]) new_value = self.get_value(item["value"], existing_item) if self.field.key_type: self.field.key_type.validate(item["key"]) if self.field.value_type: self.field.value_type.validate(new_value) existing[item["key"]] = new_value return existing
def field_converter(field, value, context): field.field.__name__ = field.__name__ if isinstance(value, dict) and "op" in value: if not isinstance(value, dict): raise ValueDeserializationError(field, value, "Not an object") operation_name = value.get("op", "undefined") if operation_name == "multi": operation = query_adapter(field, field.operation_type, name=operation_name) if operation is None: raise ValueDeserializationError( field, value, f'"{operation_name}" not a valid operation') value = operation(context, value.get("value")) else: bound_field = field.field.bind(context) operation = query_adapter(bound_field, field.operation_type, name=operation_name) if operation is None: raise ValueDeserializationError( field, value, f'"{operation_name}" not a valid operation') value = operation(context, value.get("value")) elif isinstance(value, (dict, list)): value = get_adapter(field.field, IJSONToValue, args=[value, context]) return value
def _validate_field(field, context, value): if 'key' not in value or 'value' not in value: raise ValueDeserializationError( field, value, f'Invalid data') from guillotina.behaviors.dynamic import find_field field = find_field(context, value['key']) # now, verify value... if not field: raise ValueDeserializationError( field, value, f'Dynamic field not found') field_type = field.get('type', 'unknown') try: valid_type = namedtuple( 'temp_assign_type', [field_type]) ob = valid_type({field_type: None}) bound_field = IDynamicType[field_type].bind(ob) # validate and convert real_value = get_adapter( bound_field, IJSONToValue, args=[value['value'], ob]) bound_field.validate(real_value) value['value'] = real_value except (KeyError, ComponentLookupError): raise ValueDeserializationError( field, value, f'Invalid type {field_type}')
def field_converter(field, value, context): if not isinstance(value, dict): raise ValueDeserializationError(field, value, 'Not an object') operation_name = value.get('op', 'undefined') operation = query_adapter(field, IPatchFieldOperation, name=operation_name) if operation is None: raise ValueDeserializationError( field, value, f'"{operation_name}" not a valid operation') if 'value' not in value: raise ValueDeserializationError(field, value, f'Mising value') return value
async def __call__(self, field_context, context, value): existing = self.get_existing_value(field_context) if "bucket_index" not in value or "item_index" not in value: raise ValueDeserializationError(self.field, value, "Not valid remove request") try: await existing.remove(context, value["bucket_index"], value["item_index"]) except IndexError: raise ValueDeserializationError(self.field, value, "Not valid index value")
async def __call__(self, field_context, context, value): existing = self.get_existing_value(field_context) if 'bucket_index' not in value or 'item_index' not in value: raise ValueDeserializationError(self.field, value, 'Not valid remove request') try: await existing.remove(context, value['bucket_index'], value['item_index']) except IndexError: raise ValueDeserializationError(self.field, value, 'Not valid index value')
def field_converter(field, value, context): if not isinstance(value, dict): raise ValueDeserializationError( field, value, "Not valid patch operation definition") operation_name = value.get("op", "undefined") operation = query_adapter(field, IPatchFieldOperation, name=operation_name) if operation is None: raise ValueDeserializationError( field, value, f'"{operation_name}" not a valid operation') if "value" not in value: raise ValueDeserializationError(field, value, f"Missing value") return value
def __call__(self, context, value): existing = self.field.query(context) if existing is None: existing = self.field.missing_value or [] if not isinstance(value, list): # pragma: no cover raise ValueDeserializationError(self.field, value, "Not valid list") if self.field.max_ops and len(value) > self.field.max_ops: raise ValueDeserializationError( self.field, value, f"Exceeded max allowed operations for field: {self.field.max_ops}" ) return self.do_operation(existing, value)
def do_operation(self, existing, value): try: existing.remove(value) except ValueError: raise ValueDeserializationError(self.field, value, "{} not in value".format(value)) return existing
def do_operation(self, existing, value): try: del existing[value] except (IndexError, TypeError): # pragma: no cover raise ValueDeserializationError(self.field, value, "Not valid index value") return existing
def __call__(self, context, value): existing = getattr(context, self.field.__name__, None) or {} try: del existing[value] except IndexError: raise ValueDeserializationError(self.field, value, 'Not valid index value') return existing
def field_converter(field, value, context): field.field.__name__ = field.__name__ if isinstance(value, dict) and 'op' in value: if not isinstance(value, dict): raise ValueDeserializationError(field, value, 'Not an object') operation_name = value.get('op', 'undefined') bound_field = field.field.bind(context) operation = query_adapter( bound_field, field.operation_type, name=operation_name) if operation is None: raise ValueDeserializationError( field, value, f'"{operation_name}" not a valid operation') value = operation(context, value.get('value')) elif isinstance(value, (dict, list)): value = get_adapter(field.field, IJSONToValue, args=[value, context]) return value
def __call__(self, context, value): if self.field.max_ops and len(value) > self.field.max_ops: raise ValueDeserializationError( self.field, value, f"Exceeded max allowed operations for field: {self.field.max_ops}" ) bound_field = self.field.field.bind(context) resulting_value = None for op in value: if not isinstance(op, dict) or "op" not in op: raise ValueDeserializationError(self.field, value, f"{op} not a valid operation") resulting_value = field_converter(self.field, op, context) bound_field.set(context, resulting_value) return resulting_value
def dict_converter(field, value, context=None): if value == {}: return {} if not isinstance(value, dict): raise ValueDeserializationError(field, value, "Not an object") result = {} for key in value.keys(): if getattr(field, "key_type", None) and getattr( field.key_type, "_type", None): if not isinstance(key, field.key_type._type): raise ValueDeserializationError(field, value, "Invalid key type provided") result[key] = _optimized_lookup(value[key], field.value_type, context) return result
def __call__(self, context, value): if not isinstance(value, list): raise ValueDeserializationError( self.field, value, f"Invalid type patch data, must be list of updates" ) for item in value: _validate_field(self.field, context, item) return super().__call__(context, value)
def __call__(self, context, value): existing = self.field.query(context) or {} try: del existing[value] except (IndexError, KeyError, TypeError): raise ValueDeserializationError(self.field, value, "Not valid index value") return existing
def __call__(self, context, value): existing = getattr(context, self.field.__name__, None) or {} try: existing.remove(value) except ValueError: raise ValueDeserializationError(self.field, value, '{} not in value'.format(value)) return existing
def __call__(self, context, value): if self.field.key_type: self.field.key_type.validate(value) existing = getattr(context, self.field.__name__, None) try: del existing[value] except (IndexError, KeyError): raise ValueDeserializationError(self.field, value, 'Not valid index value') return existing
def union_converter(field, value, context=None): for f in field.fields: try: val = schema_compatible(value, f) if f.__implemented__(IObject) and value and not val: continue # IObject doesn't match return val except Exception: pass raise ValueDeserializationError(field, value, "Doesn't match any field")
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")
async def __call__(self, field_context, context, value): if self.field.key_type: self.field.key_type.validate(value) existing = self.get_existing_value(field_context) try: await existing.remove(context, value) except (IndexError, KeyError): raise ValueDeserializationError(self.field, value, "Not valid index value")
def __call__(self, context, value): if "key" not in value or "value" not in value: raise ValueDeserializationError(self.field, value, "Not valid patch value") existing = self.field.query(context) if existing is None: existing = self.field.missing_value or {} existing[value["key"]] = value["value"] return existing
def _validate_field(field, context, value): if "key" not in value or "value" not in value: raise ValueDeserializationError(field, value, f"Invalid data") from guillotina.behaviors.dynamic import find_field field = find_field(context, value["key"]) # now, verify value... if not field: raise ValueDeserializationError(field, value, f"Dynamic field not found") field_type = field.get("type", "unknown") try: valid_type = namedtuple("temp_assign_type", [field_type]) ob = valid_type({field_type: None}) bound_field = IDynamicType[field_type].bind(ob) # validate and convert real_value = get_adapter(bound_field, IJSONToValue, args=[value["value"], ob]) bound_field.validate(real_value) value["value"] = real_value except (KeyError, ComponentLookupError): raise ValueDeserializationError(field, value, f"Invalid type {field_type}")
def object_converter(field, value, context=None): if not isinstance(value, dict): raise ValueDeserializationError(field, value, "Not an object") result = {} for key, val in value.items(): if key in field.schema: f = field.schema[key] if val is not None: result[key] = _optimized_lookup(val, f, context) else: result[key] = None return result
async def get_value(self, field, obj, value): if value is None: return None try: 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 object_converter(field, value, context=None): if not isinstance(value, dict): raise ValueDeserializationError(field, value, 'Not an object') result = {} for key, val in value.items(): if key in field.schema: f = field.schema[key] if val is not None: result[key] = get_adapter(f, IJSONToValue, args=[val, context]) else: result[key] = None return result
def schema_compatible(value, schema_or_field, context=None): """The schema_compatible function converts any value to guillotina.schema compatible data when possible, raising a TypeError for unsupported values. This is done by using the ISchemaCompatible converters. """ if value is None: return value try: return get_adapter(schema_or_field, IJSONToValue, args=[value, context]) except ComponentLookupError: raise ValueDeserializationError( schema_or_field, value, 'Deserializer not found for field')
async def __call__(self, field_context, context, value): existing = self.get_existing_value(field_context) if not isinstance(value, list): raise ValueDeserializationError(self.field, value, "Not valid list") if self.field.max_ops and len(value) > self.field.max_ops: raise ValueDeserializationError( self.field, value, f"Exceeded max allowed operations for field: {self.field.max_ops}" ) values = [] for item in value: if self.field.value_type: item_value = self.get_value(item, None, field_type=self.field.value_type) self.field.value_type.validate(item_value) values.append(item_value) await existing.extend(context, values)