Пример #1
0
 def testAreSameMessageType_withDifferentMessageType_returnsFalse(self):
   """Test are_same_message_type with two different message types."""
   patient = patient_pb2.Patient()
   uscore_patient_profile = uscore_pb2.USCorePatientProfile()
   self.assertFalse(
       proto_utils.are_same_message_type(patient.DESCRIPTOR,
                                         uscore_patient_profile.DESCRIPTOR))
   self.assertFalse(
       proto_utils.are_same_message_type(patient_pb2.Patient.DESCRIPTOR,
                                         uscore_patient_profile.DESCRIPTOR))
Пример #2
0
 def testAreSameMessageType_withSameMessageType_returnsTrue(self):
   """Test are_same_message_type with the same message types."""
   patient_a = patient_pb2.Patient()
   patient_b = patient_pb2.Patient()
   self.assertTrue(
       proto_utils.are_same_message_type(patient_a.DESCRIPTOR,
                                         patient_b.DESCRIPTOR))
   self.assertTrue(
       proto_utils.are_same_message_type(patient_pb2.Patient.DESCRIPTOR,
                                         patient_pb2.Patient.DESCRIPTOR))
Пример #3
0
 def testGetMessageClassFromDescriptor_returnsMessageClass(self):
   """Tests that the correct class is returned for a message."""
   actual = proto_utils.get_message_class_from_descriptor(
       patient_pb2.Patient.DESCRIPTOR)
   self.assertTrue(
       proto_utils.are_same_message_type(actual.DESCRIPTOR,
                                         patient_pb2.Patient.DESCRIPTOR))
 def __init__(self, wrapped: message.Message, context: Context):
     """Converts wrapped into an instance of context.code_cls and wraps."""
     if not proto_utils.are_same_message_type(wrapped.DESCRIPTOR,
                                              context.code_cls.DESCRIPTOR):
         tmp = context.code_cls()
         codes.copy_code(wrapped, tmp)
         wrapped = tmp
     super(CodeWrapper, self).__init__(wrapped, context)
Пример #5
0
 def merge_into(self, target: message.Message) -> None:
   """Merges the underlying wrapped primitive into target."""
   if not proto_utils.are_same_message_type(self.wrapped.DESCRIPTOR,
                                            target.DESCRIPTOR):
     raise ValueError(f'Type mismatch in merge_into. Attempted to merge '
                      f'{self.wrapped.DESCRIPTOR.full_name} into '
                      f'{target.DESCRIPTOR.full_name}.')
   target.MergeFrom(self.wrapped)
Пример #6
0
def copy_coding(source: message.Message, target: message.Message):
    """Copies all fields from source to target "Coding" messages.

  Args:
    source: The FHIR coding instance to copy from.
    target: The FHIR coding instance to copy to.

  Raises:
    InvalidFhirError: In the event that source or target is not a type/profile
    of Coding.
  """
    if not fhir_types.is_type_or_profile_of_coding(source.DESCRIPTOR):
        raise fhir_errors.InvalidFhirError(
            f'Source: {source.DESCRIPTOR.full_name} '
            'is not a type or profile of Coding.')

    if not fhir_types.is_type_or_profile_of_coding(target.DESCRIPTOR):
        raise fhir_errors.InvalidFhirError(
            f'Target: {target.DESCRIPTOR.full_name} '
            'is not a type or profile of Coding.')

    if proto_utils.are_same_message_type(source.DESCRIPTOR, target.DESCRIPTOR):
        target.CopyFrom(source)
        return

    # Copy fields present in both profiled and unprofiled codings.
    proto_utils.copy_common_field(source, target, 'id')
    proto_utils.copy_common_field(source, target, 'extension')
    proto_utils.copy_common_field(source, target, 'version')
    proto_utils.copy_common_field(source, target, 'display')
    proto_utils.copy_common_field(source, target, 'user_selected')

    # Copy the "code" field from source to target
    source_code = proto_utils.get_value_at_field(source, 'code')
    copy_code(source_code, proto_utils.set_in_parent_or_add(target, 'code'))

    target_system_field = target.DESCRIPTOR.fields_by_name.get('system')

    # TODO: This will fail if there is a target system field,
    # *and* a source system field, since in this case the source code will not
    # contain the system information, the containing Coding would.  In general,
    # it's not quite right to get the system from Code, since unprofiled codes
    # don't contain system information.  In practice, this isn't a problem,
    # because the only kind of profiled Codings we currently support are
    # Codings with typed Codes (which contain source information) but this is
    # not neccessary according to FHIR spec.
    if target_system_field is not None:
        source_system_str = get_system_for_code(source_code)
        target_system_uri = proto_utils.set_in_parent_or_add(
            target, target_system_field)
        proto_utils.set_value_at_field(target_system_uri, 'value',
                                       source_system_str)
Пример #7
0
def copy_coding(source: message.Message, target: message.Message):
    """Copies all fields from source to target "Coding" messages.

  Args:
    source: The FHIR coding instance to copy from.
    target: The FHIR coding instance to copy to.

  Raises:
    InvalidFhirError: In the event that source or target is not a type/profile
    of Coding.
  """
    if not fhir_types.is_type_or_profile_of_coding(source.DESCRIPTOR):
        raise fhir_errors.InvalidFhirError(
            f'Source: {source.DESCRIPTOR.full_name} '
            'is not a type or profile of Coding.')

    if not fhir_types.is_type_or_profile_of_coding(target.DESCRIPTOR):
        raise fhir_errors.InvalidFhirError(
            f'Target: {target.DESCRIPTOR.full_name} '
            'is not a type or profile of Coding.')

    if proto_utils.are_same_message_type(source.DESCRIPTOR, target.DESCRIPTOR):
        target.CopyFrom(source)
        return

    # Copy fields present in both profiled and unprofiled codings.
    proto_utils.copy_common_field(source, target, 'id')
    proto_utils.copy_common_field(source, target, 'extension')
    proto_utils.copy_common_field(source, target, 'version')
    proto_utils.copy_common_field(source, target, 'display')
    proto_utils.copy_common_field(source, target, 'user_selected')

    # Copy the "code" field from source to target
    source_code = proto_utils.get_value_at_field(source, 'code')
    copy_code(source_code, proto_utils.set_in_parent_or_add(target, 'code'))

    target_system_field = target.DESCRIPTOR.fields_by_name.get('system')
    if target_system_field is not None:
        source_system_str = get_system_for_code(source_code)
        target_system_uri = proto_utils.set_in_parent_or_add(
            target, target_system_field)
        proto_utils.set_value_at_field(target_system_uri, 'value',
                                       source_system_str)
Пример #8
0
def copy_code(source: message.Message, target: message.Message):
    """Adds all fields from source to target.

  Args:
    source: The FHIR Code instance to copy from.
    target: The target FHIR Code instance to copy to.
  """
    if not fhir_types.is_type_or_profile_of_code(source.DESCRIPTOR):
        raise fhir_errors.InvalidFhirError(
            f'Source: {source.DESCRIPTOR.full_name} '
            'is not type or profile of Code.')

    if not fhir_types.is_type_or_profile_of_code(target.DESCRIPTOR):
        raise fhir_errors.InvalidFhirError(
            f'Target: {target.DESCRIPTOR.full_name} '
            'is not type or profile of Code.')

    if proto_utils.are_same_message_type(source.DESCRIPTOR, target.DESCRIPTOR):
        target.CopyFrom(source)
        return

    source_value_field = source.DESCRIPTOR.fields_by_name.get('value')
    target_value_field = target.DESCRIPTOR.fields_by_name.get('value')
    if source_value_field is None or target_value_field is None:
        raise fhir_errors.InvalidFhirError(
            'Unable to copy code from '
            f'{source.DESCRIPTOR.full_name} '
            f'to {target.DESCRIPTOR.full_name}.')

    proto_utils.copy_common_field(source, target, 'id')
    proto_utils.copy_common_field(source, target, 'extension')

    # Handle specialized codes
    if (source_value_field.type not in _CODE_TYPES
            or target_value_field.type not in _CODE_TYPES):
        raise ValueError(
            f'Unable to copy from {source.DESCRIPTOR.full_name} '
            f'to {target.DESCRIPTOR.full_name}. Must have a field '
            'of TYPE_ENUM or TYPE_STRING.')

    source_value = proto_utils.get_value_at_field(source, source_value_field)
    if source_value_field.type == target_value_field.type:
        # Perform a simple assignment if value_field types are equivalent
        proto_utils.set_value_at_field(target, target_value_field,
                                       source_value)
    else:
        # Otherwise, we need to transform the value prior to assignment...
        if source_value_field.type == descriptor.FieldDescriptor.TYPE_STRING:
            source_enum_value = code_string_to_enum_value_descriptor(
                source_value, target_value_field.enum_type)
            proto_utils.set_value_at_field(target, target_value_field,
                                           source_enum_value.number)
        elif source_value_field.type == descriptor.FieldDescriptor.TYPE_ENUM:
            source_string_value = enum_value_descriptor_to_code_string(
                source_value_field.enum_type.values_by_number[source_value])
            proto_utils.set_value_at_field(target, target_value_field,
                                           source_string_value)
        else:  # Should never hit
            raise ValueError('Unexpected generic value field type: '
                             f'{source_value_field.type}. Must be a field of '
                             'TYPE_ENUM or TYPE_STRING in order to copy.')
Пример #9
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)
Пример #10
0
 def get_primitive_wrapper_cls_for_primitive_cls(
     self, primitive_cls: Type[message.Message]
 ) -> Type[_primitive_wrappers.PrimitiveWrapper]:
     if fhir_types.is_type_or_profile_of_code(primitive_cls.DESCRIPTOR):
         return _primitive_wrappers.CodeWrapper
     elif proto_utils.are_same_message_type(
             primitive_cls.DESCRIPTOR, self.base64_binary_cls.DESCRIPTOR):
         return _base64_binary.Base64BinaryWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.boolean_cls.DESCRIPTOR):
         return _primitive_wrappers.BooleanWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.date_cls.DESCRIPTOR):
         return _date.DateWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.canonical_cls.DESCRIPTOR):
         return _primitive_wrappers.StringLikePrimitiveWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.date_time_cls.DESCRIPTOR):
         return _date_time.DateTimeWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.decimal_cls.DESCRIPTOR):
         return _decimal.DecimalWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.id_cls.DESCRIPTOR):
         return _primitive_wrappers.StringLikePrimitiveWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.instant_cls.DESCRIPTOR):
         return _instant.InstantWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.integer_cls.DESCRIPTOR):
         return _primitive_wrappers.IntegerLikePrimitiveWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.markdown_cls.DESCRIPTOR):
         return _primitive_wrappers.StringLikePrimitiveWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.oid_cls.DESCRIPTOR):
         return _primitive_wrappers.StringLikePrimitiveWrapper
     elif proto_utils.are_same_message_type(
             primitive_cls.DESCRIPTOR, self.positive_int_cls.DESCRIPTOR):
         return _primitive_wrappers.IntegerLikePrimitiveWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.string_cls.DESCRIPTOR):
         return _primitive_wrappers.StringLikePrimitiveWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.time_cls.DESCRIPTOR):
         return _time.TimeWrapper
     elif proto_utils.are_same_message_type(
             primitive_cls.DESCRIPTOR, self.unsigned_int_cls.DESCRIPTOR):
         return _primitive_wrappers.IntegerLikePrimitiveWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.uri_cls.DESCRIPTOR):
         return _primitive_wrappers.StringLikePrimitiveWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.url_cls.DESCRIPTOR):
         return _primitive_wrappers.StringLikePrimitiveWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.uuid_cls.DESCRIPTOR):
         return _primitive_wrappers.StringLikePrimitiveWrapper
     elif proto_utils.are_same_message_type(primitive_cls.DESCRIPTOR,
                                            self.xhtml_cls.DESCRIPTOR):
         return _primitive_wrappers.XhtmlWrapper
     raise ValueError(
         f'Unexpected R4 FHIR primitive: {primitive_cls.DESCRIPTOR.full_name!r} '
         f'for handler: {type(self)}.')