Esempio n. 1
0
 def testCopyCoding_fromGenericToGeneric(self, name: str):
     """Tests copy_coding from a generic Coding to a generic Coding."""
     source = self._coding_from_file(name + '_raw.prototxt',
                                     datatypes_pb2.Coding)
     target = datatypes_pb2.Coding()
     codes.copy_coding(source, target)
     self.assertEqual(source, target)
Esempio n. 2
0
 def testCopyCoding_fromTypedToTyped(self, name: str):
     """Tests copy_coding from a typed Coding to a Typed Coding."""
     source = self._coding_from_file(
         name + '_typed.prototxt',
         uscore_pb2.PatientUSCoreRaceExtension.OmbCategoryCoding)
     target = uscore_pb2.PatientUSCoreRaceExtension.OmbCategoryCoding()
     codes.copy_coding(source, target)
     self.assertEqual(source, target)
Esempio n. 3
0
    def testCopyCoding_fromTypedToGeneric(self, name: str):
        """Tests copy_coding from a typed Coding to a generic Coding."""
        generic_golden = self._coding_from_file(name + '_raw.prototxt',
                                                datatypes_pb2.Coding)
        typed = self._coding_from_file(
            name + '_typed.prototxt',
            uscore_pb2.PatientUSCoreRaceExtension.OmbCategoryCoding)

        generic = datatypes_pb2.Coding()
        codes.copy_coding(typed, generic)
        self.assertEqual(generic_golden, generic)
Esempio n. 4
0
def _add_value_to_extension(msg: message.Message, extension: message.Message,
                            is_choice_type: bool):
    """Adds the fields from msg to a generic Extension.

  Attempts are first made to set the "value" field of the generic Extension
  based on the type of field set on message. If this fails, checks are made
  against the generic Code and Coding types, and finally we fall back to adding
  the message's fields as sub-extensions.

  Args:
    msg: The message whose values to add to extension.
    extension: The generic Extension to populate.
    is_choice_type: Whether or not the provided message represents a "choice"
    type.
  """
    if is_choice_type:
        oneofs = msg.DESCRIPTOR.oneofs
        if not oneofs:
            raise fhir_errors.InvalidFhirError(
                f'Choice type is missing a oneof: {msg.DESCRIPTOR.full_name}')
        value_field_name = msg.WhichOneof(oneofs[0].name)
        if value_field_name is None:
            raise ValueError('Choice type has no value set: '
                             f'{msg.DESCRIPTOR.full_name}')
        value_field = msg.DESCRIPTOR.fields_by_name[value_field_name]
        _verify_field_is_proto_message_type(value_field)
        _add_value_to_extension(
            proto_utils.get_value_at_field(msg, value_field), extension, False)
    else:
        # Try to set the message directly as a datatype value on the extension.
        # E.g., put the message of type Boolean into the value.boolean field
        value_field_mapping = _get_value_field_mapping_for_extension(extension)
        value_field = value_field_mapping.get(msg.DESCRIPTOR.full_name)
        if value_field is not None:
            proto_utils.set_value_at_field(
                cast(Any, extension).value, value_field, msg)
        elif annotation_utils.has_fhir_valueset_url(msg):
            codes.copy_code(msg, cast(Any, extension).value.code)
        elif fhir_types.is_type_or_profile_of_coding(msg):
            codes.copy_coding(msg, cast(Any, extension).value.coding)
        else:  # Fall back to adding individual fields as sub-extensions
            _add_fields_to_extension(msg, extension)
Esempio n. 5
0
def _add_extension_value_to_message(extension: message.Message,
                                    msg: message.Message,
                                    message_field: descriptor.FieldDescriptor):
    """Serialize the provided extension and add it to the message.

  Args:
    extension: The FHIR extension to serialize.
    msg: The message to add the serialized extension to.
    message_field: The field on the message to set.

  Raises:
    InvalidFhirError: In the event that the field to be set is not a singular
    message type, or if the provided extension is not singular (has nested
    extensions).
  """
    if message_field.type != descriptor.FieldDescriptor.TYPE_MESSAGE:
        raise fhir_errors.InvalidFhirError(
            f'{msg.DESCRIPTOR.full_name} is not a FHIR extension type.')

    extension_field = extension.DESCRIPTOR.fields_by_name['extension']
    if proto_utils.field_content_length(extension, extension_field) > 0:
        raise fhir_errors.InvalidFhirError(
            'No child extensions should be set on '
            f'{extension.DESCRIPTOR.full_name}.')

    value_field = _get_populated_extension_value_field(extension)

    # If a choice type, need to assign the extension value to the correct field.
    if annotation_utils.is_choice_type_field(message_field):
        choice_message = proto_utils.get_value_at_field(msg, message_field)
        choice_descriptor = choice_message.DESCRIPTOR

        for choice_field in choice_descriptor.fields:
            if (value_field.message_type.full_name ==
                    choice_field.message_type.full_name):
                _add_extension_value_to_message(extension, choice_message,
                                                choice_field)
                return

        raise ValueError(
            f'No field on Choice Type {choice_descriptor.full_name} '
            f'for extension {extension.DESCRIPTOR.full_name}.')

    # If the target message is a bound Code type, we need to convert the generic
    # Code field from the extension into the target typed Code.
    if annotation_utils.has_fhir_valueset_url(message_field.message_type):
        typed_code = proto_utils.set_in_parent_or_add(msg, message_field)
        codes.copy_code(cast(Any, extension).value.code, typed_code)
        return

    # If the target message is bound to a Coding type, we must convert the generic
    # Coding field from the extension into the target typed Coding.
    if fhir_types.is_type_or_profile_of_coding(message_field.message_type):
        typed_coding = proto_utils.set_in_parent_or_add(msg, message_field)
        codes.copy_coding(cast(Any, extension).value.coding, typed_coding)
        return

    # Value types must match
    if not proto_utils.are_same_message_type(value_field.message_type,
                                             message_field.message_type):
        raise ValueError(
            'Missing expected value of type '
            f'{message_field.message_type.full_name} in extension '
            f'{extension.DESCRIPTOR.full_name}.')

    value = proto_utils.get_value_at_field(
        cast(Any, extension).value, value_field)
    if proto_utils.field_is_repeated(message_field):
        proto_utils.append_value_at_field(msg, message_field, value)
    else:
        proto_utils.set_value_at_field(msg, message_field, value)