async def get_schema(self, schema, context, result, behavior): read_permissions = merged_tagged_value_dict(schema, read_permission.key) schema_serial = {} for name, field in get_fields(schema).items(): if not self.check_permission(read_permissions.get(name)): continue if behavior: # omit/include for behaviors need full name dotted_name = schema.__identifier__ + '.' + name else: dotted_name = name if ('*' not in self.include and (dotted_name in self.omit or ( len(self.include) > 0 and ( dotted_name not in self.include and schema.__identifier__ not in self.include)))): # make sure the fields aren't filtered continue value = await self.serialize_field(context, field) if not behavior: result[name] = value else: schema_serial[name] = value if behavior and len(schema_serial) > 0: result[schema.__identifier__] = schema_serial
async def get_schema(self, schema, context, result, behavior): read_permissions = merged_tagged_value_dict(schema, read_permission.key) schema_serial = {} for name, field in get_fields(schema).items(): if not self.check_permission(read_permissions.get(name)): continue if behavior: # omit/include for behaviors need full name dotted_name = schema.__identifier__ + '.' + name else: dotted_name = name if ('*' not in self.include and (dotted_name in self.omit or (len(self.include) > 0 and (dotted_name not in self.include and schema.__identifier__ not in self.include)))): # make sure the fields aren't filtered continue value = await self.serialize_field(context, field) if not behavior: result[name] = value else: schema_serial[name] = value if behavior and len(schema_serial) > 0: result[schema.__identifier__] = schema_serial
def fhir_field_from_schema( schema: Interface, resource_type: str = None ) -> Union[FhirField, None]: """ """ index_fields: dict if resource_type: index_fields = directives.merged_tagged_value_dict(schema, directives.index.key) for name, field in get_fields_in_order(schema): if IFhirField.providedBy(field): if resource_type: catalog_info = index_fields.get(name, None) if catalog_info is None: continue if catalog_info.get("resource_type", None) is None: continue if catalog_info["resource_type"] != resource_type: continue return field return None
async def get_all_indices(context, request): base_url = IAbsoluteURL(context, request)() result = {"@id": base_url, "types": {}, "behaviors": {}} for type_name, type_schema in FACTORY_CACHE.items(): indices = merged_tagged_value_dict(type_schema.schema, index.key) result["types"][type_name] = { key: value["type"] for key, value in indices.items() } # noqa for behavior, utility in get_utilities_for(IBehavior): indices = merged_tagged_value_dict(utility.interface, index.key) result["behaviors"][behavior] = { key: value["type"] for key, value in indices.items() } # noqa return result
def get_indexes(): """ Get all the indexes """ global INDEXES_CACHE if INDEXES_CACHE is None: mapping = {} for type_name, type_schema in FACTORY_CACHE.items(): mapping.update( merged_tagged_value_dict(type_schema.schema, index.key)) for _, utility in get_utilities_for(IBehavior): mapping.update( merged_tagged_value_dict(utility.interface, index.key)) INDEXES_CACHE = mapping else: INDEXES_CACHE return INDEXES_CACHE
async def __call__(self, indexes=None, schemas=None): # For each type values = { 'type_name': self.content.type_name, 'tid': self.content.__serial__ } if schemas is None: schemas = iter_schemata(self.content) for schema in schemas: behavior = schema(self.content) loaded = False for field_name, index_data in merged_tagged_value_dict(schema, index.key).items(): index_name = index_data.get('index_name', field_name) if index_name in values or index_name in self.attempts: # you can override indexers so we do not want to index # the same value more than once continue self.attempts.append(index_name) try: # accessors we always reindex since we can't know if updated # from the indexes param--they are "fake" like indexes, not fields if 'accessor' in index_data: if (indexes is None or (len(set(index_data.get('fields', [])) & set(indexes)) > 0)): if not loaded: await self.load_behavior(behavior) loaded = True values[index_name] = await apply_coroutine( index_data['accessor'], behavior) elif (indexes is None or field_name in indexes or isinstance(getattr(type(self.content), field_name, None), property)): if not loaded: await self.load_behavior(behavior) loaded = True # in this case, properties are also dynamic so we have to make sure # to allow for them to be reindexed every time. values[index_name] = self.get_data(behavior, schema, field_name) except NoIndexField: pass for metadata_name in merged_tagged_value_list(schema, metadata.key): if (indexes is not None and metadata_name not in indexes and not isinstance(getattr(type(self.content), metadata_name, None), property)): # in this case, properties are also dynamic so we have to make sure # to allow for them to be reindexed every time. continue # skip if not loaded: await self.load_behavior(behavior) loaded = True try: values[metadata_name] = self.get_data(behavior, schema, metadata_name) except NoIndexField: pass return values
async def get_field_value(context, request): field_name = request.matchdict["dotted_name"] if "." in field_name: # behavior field lookup iface_dotted = ".".join(field_name.split(".")[:-1]) field_name = field_name.split(".")[-1] try: schema = resolve_dotted_name(iface_dotted) except ModuleNotFoundError: return HTTPNotFound( content={"reason": f"Could resolve: {iface_dotted}"}) try: field = schema[field_name] except KeyError: return HTTPNotFound(content={"reason": f"No field: {field_name}"}) try: behavior = await get_behavior(context, schema) except AttributeError: return HTTPNotFound( content={"reason": f"Could not load behavior: {iface_dotted}"}) if behavior is None: return HTTPNotFound( content={"reason": f"Not valid behavior: {iface_dotted}"}) field = field.bind(behavior) field_context = behavior else: # main object field factory = get_cached_factory(context.type_name) schema = factory.schema try: field = schema[field_name] except KeyError: return HTTPNotFound(content={"reason": f"No field: {field_name}"}) field = field.bind(context) field_context = context # check permission read_permissions = merged_tagged_value_dict(schema, read_permission.key) serializer = get_multi_adapter((context, request), IResourceSerializeToJson) if not serializer.check_permission(read_permissions.get(field_name)): return HTTPUnauthorized( content={"reason": "You are not authorized to render this field"}) field_renderer = query_multi_adapter((context, request, field), IFieldValueRenderer) if field_renderer is None: return await serializer.serialize_field(field_context, field) else: return await field_renderer()
def __init__(self): self.data_adapter = DefaultCatalogDataAdapter(None) self.mappings = {} for type_name, schema in get_utilities_for(IResourceFactory): self.mappings[type_name] = {} for schema in iter_schemata_for_type(type_name): for field_name, index_data in merged_tagged_value_dict( schema, directives.index.key).items(): index_name = index_data.get('index_name', field_name) self.mappings[type_name][index_name] = { 'schema': schema, 'properties': index_data }
async def get_schema(self, schema, context, result, behavior): read_permissions = merged_tagged_value_dict(schema, read_permission.key) schema_serial = {} for name, field in getFields(schema).items(): if not self.check_permission(read_permissions.get(name)): continue serializer = queryMultiAdapter((field, context, self.request), IResourceFieldSerializer) value = await serializer() if not behavior: result[name] = value else: schema_serial[name] = value if behavior: result[schema.__identifier__] = schema_serial
async def __call__(self): # For each type values = {} for schema in iter_schemata_for_type(self.content.portal_type): behavior = schema(self.content) for index_name, index_data in merged_tagged_value_dict( schema, index.key).items(): try: if 'accessor' in index_data: values[index_name] = await apply_coroutine( index_data['accessor'], behavior) else: values[index_name] = self.get_data( behavior, schema, index_name) except NoIndexField: pass for metadata_name in merged_tagged_value_list( schema, metadata.key): values[metadata_name] = self.get_data(behavior, schema, metadata_name) return values
async def set_schema( self, schema, obj, data, errors, validate_all=False, behavior=False): write_permissions = merged_tagged_value_dict(schema, write_permission.key) for name, field in get_fields(schema).items(): if field.readonly: continue if behavior: found = False if schema.__identifier__ in data: sdata = data[schema.__identifier__] data_value = sdata[name] if name in sdata else None found = True if name in sdata else False else: data_value = data[name] if name in data else None found = True if name in data else False f = schema.get(name) if found: if not self.check_permission(write_permissions.get(name)): continue try: value = await self.get_value(f, obj, data_value) except ValueError as e: errors.append({ 'message': e.message, 'field': name, 'error': e}) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e}) except ValueDeserializationError as e: errors.append({ 'message': e.message, 'field': name, 'error': e}) except Invalid as e: errors.append({ 'message': e.args[0], 'field': name, 'error': e}) else: # record object changes for potential future conflict resolution try: await apply_coroutine(field.set, obj, value) except Exception: logger.warning( 'Error setting data on field, falling back to setattr', exc_info=True) setattr(obj, name, value) else: if f.required and not hasattr(obj, name): errors.append({ 'message': 'Required parameter', 'field': name, 'error': ValueError('Required parameter')}) if validate_all: invariant_errors = [] try: schema.validateInvariants(object, invariant_errors) except Invalid: # Just collect errors pass validation = [(None, e) for e in invariant_errors] if len(validation): for e in validation: errors.append({ 'message': e[1].doc(), 'field': e[0], 'error': e })
def get_index_fields(type_name): mapping = {} for schema in get_all_possible_schemas_for_type(type_name): # create mapping for content type mapping.update(merged_tagged_value_dict(schema, index.key)) return mapping
async def set_schema( self, schema: Type[Interface], obj: IResource, data: Dict[str, Any], errors: List[Dict[str, Any]], validate_all: bool = False, behavior: bool = False, ): write_permissions = merged_tagged_value_dict(schema, write_permission.key) changed = False for name, field in get_fields(schema).items(): if name in RESERVED_ATTRS: continue if field.readonly: continue if behavior: found = False if data.get(schema.__identifier__): sdata = data[schema.__identifier__] data_value = sdata[name] if name in sdata else None found = True if name in sdata else False else: data_value = data[name] if name in data else None found = True if name in data else False if found: if not self.check_permission(write_permissions.get(name)): raise Unauthorized("Write permission not allowed") try: field = field.bind(obj) value = await self.get_value(field, obj, data_value) except ValueError as e: errors.append({ "message": "Value error", "field": name, "error": e }) except ValidationError as e: errors.append(e.json()) except ValueDeserializationError as e: errors.append({ "message": e.message, "field": name, "error": e }) except Invalid as e: errors.append({ "message": e.args[0], "field": name, "error": e }) else: # record object changes for potential future conflict resolution try: await apply_coroutine(field.set, obj, value) changed = True except ValidationError as e: errors.append(e.json()) except ValueDeserializationError as e: errors.append({ "message": e.message, "field": name, "error": e }) except AttributeError: logger.warning( f"AttributeError setting data on field {name}", exc_info=True) except Exception: logger.warning( f"Unhandled error setting data on field, {schema} {name}", exc_info=True) errors.append({ "message": "Unhandled exception", "field": name, "error": ValueDeserializationError(field, value, "Unhandled error"), }) else: if validate_all and field.required and getattr( obj, name, None) is None: errors.append({ "message": "Required parameter", "field": name, "error": ValueError("Required parameter"), }) for error in await validate_invariants(schema, obj): if isinstance(error, ValidationError): errors.append({ "message": error.doc(), "value": error.value, "field": error.field_name, "error": error.errors, }) else: if len(getattr(error, "args", [])) > 0 and isinstance( error.args[0], str): message = error.args[0] else: message = error.__doc__ errors.append({"message": message, "error": error}) if changed: obj.register()
async def set_schema(self, schema, obj, data, errors, validate_all=False, behavior=False): write_permissions = merged_tagged_value_dict(schema, write_permission.key) for name, field in get_fields(schema).items(): if name in RESERVED_ATTRS: continue if field.readonly: continue if behavior: found = False if schema.__identifier__ in data: sdata = data[schema.__identifier__] data_value = sdata[name] if name in sdata else None found = True if name in sdata else False else: data_value = data[name] if name in data else None found = True if name in data else False if found: if not self.check_permission(write_permissions.get(name)): raise Unauthorized('Write permission not allowed') try: field = field.bind(obj) value = await self.get_value(field, obj, data_value) except ValueError as e: errors.append({ 'message': 'Value error', 'field': name, 'error': e }) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e }) except ValueDeserializationError as e: errors.append({ 'message': e.message, 'field': name, 'error': e }) except Invalid as e: errors.append({ 'message': e.args[0], 'field': name, 'error': e }) else: # record object changes for potential future conflict resolution try: await notify(BeforeFieldModifiedEvent(field, value)) await apply_coroutine(field.set, obj, value) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e }) except ValueDeserializationError as e: errors.append({ 'message': e.message, 'field': name, 'error': e }) except AttributeError: logger.warning( f'AttributeError setting data on field {name}', exc_info=True) except Exception: if not isinstance(getattr(type(obj), name, None), property): # we can not set data on properties logger.warning( 'Error setting data on field, falling back to setattr', exc_info=True) setattr(obj, name, value) else: logger.warning('Error setting data on field', exc_info=True) else: if validate_all and field.required and getattr( obj, name, None) is None: errors.append({ 'message': 'Required parameter', 'field': name, 'error': ValueError('Required parameter') }) if validate_all: invariant_errors = [] try: schema.validateInvariants(object, invariant_errors) except Invalid: # Just collect errors pass validation = [(None, e) for e in invariant_errors] if len(validation): for error in validation: errors.append({ 'message': error[1].doc(), 'field': error[0], 'error': error })
async def set_schema( self, schema, obj, data, errors, validate_all=False, behavior=False): write_permissions = merged_tagged_value_dict(schema, write_permission.key) for name, field in get_fields(schema).items(): if name in RESERVED_ATTRS: continue if field.readonly: continue if behavior: found = False if schema.__identifier__ in data: sdata = data[schema.__identifier__] data_value = sdata[name] if name in sdata else None found = True if name in sdata else False else: data_value = data[name] if name in data else None found = True if name in data else False if found: if not self.check_permission(write_permissions.get(name)): raise Unauthorized('Write permission not allowed') try: field = field.bind(obj) value = await self.get_value(field, obj, data_value) except ValueError as e: errors.append({ 'message': 'Value error', 'field': name, 'error': e}) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e}) except ValueDeserializationError as e: errors.append({ 'message': e.message, 'field': name, 'error': e}) except Invalid as e: errors.append({ 'message': e.args[0], 'field': name, 'error': e}) else: # record object changes for potential future conflict resolution try: await apply_coroutine(field.set, obj, value) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e}) except ValueDeserializationError as e: errors.append({ 'message': e.message, 'field': name, 'error': e}) except AttributeError: logger.warning( f'AttributeError setting data on field {name}', exc_info=True) except Exception: if not isinstance(getattr(type(obj), name, None), property): # we can not set data on properties logger.warning( 'Error setting data on field, falling back to setattr', exc_info=True) setattr(obj, name, value) else: logger.warning( 'Error setting data on field', exc_info=True) else: if validate_all and field.required and getattr(obj, name, None) is None: errors.append({ 'message': 'Required parameter', 'field': name, 'error': ValueError('Required parameter')}) if validate_all: invariant_errors = [] try: schema.validateInvariants(object, invariant_errors) except Invalid: # Just collect errors pass validation = [(None, e) for e in invariant_errors] if len(validation): for error in validation: errors.append({ 'message': error[1].doc(), 'field': error[0], 'error': error })
async def set_schema(self, schema, obj, data, errors, validate_all=False, behavior=False): write_permissions = merged_tagged_value_dict(schema, write_permission.key) for name, field in getFields(schema).items(): if field.readonly: continue if behavior: data_value = data[schema.__identifier__][name] if name in data[ schema.__identifier__] else None # noqa found = True if name in data[schema.__identifier__] else False else: data_value = data[name] if name in data else None found = True if name in data else False f = schema.get(name) if found: if not self.check_permission(write_permissions.get(name)): continue # Deserialize to field value deserializer = queryMultiAdapter((f, obj, self.request), IResourceFieldDeserializer) if deserializer is None: continue try: value = deserializer(data_value) except ValueError as e: errors.append({ 'message': e.message, 'field': name, 'error': e }) except ValidationError as e: errors.append({ 'message': e.doc(), 'field': name, 'error': e }) except Invalid as e: errors.append({ 'message': e.args[0], 'field': name, 'error': e }) else: try: field.set(obj, value) except: # noqa setattr(obj, name, value) else: if f.required and not hasattr(obj, name): errors.append({ 'message': 'Required parameter', 'field': name, 'error': ValueError('Required parameter') }) if validate_all: invariant_errors = [] try: schema.validateInvariants(object, invariant_errors) except Invalid: # Just collect errors pass validation = [(None, e) for e in invariant_errors] if len(validation): for e in validation: errors.append({ 'message': e[1].doc(), 'field': e[0], 'error': e })