def test_assign_wrong_component_to_known_position(self): f1 = Field('pid_10', validation_level=VALIDATION_LEVEL.STRICT) with self.assertRaises(ChildNotValid): f1.ce_1 = Component('CX_1') f2 = Field('pid_3') with self.assertRaises(ChildNotValid): #this one is not raised!!! f2.cx_1 = Component('HD_1') f2.cx_1 = Component('CX_1')
def test_wrong_z_field(self): """ Tests that Fields of None datatype are not validated """ f = Field('zin_1') f.value = 'aa^bb' self.assertRaises(ValidationError, f.validate, report_file=self.report_file) self._test_report_file('ERROR')
def test_to_string_msh_field(self): m = Message('OML_O33') msh = m.msh self.assertEqual(msh.msh_1.to_er7(), '|') self.assertEqual(msh.msh_2.to_er7(), '^~\\&') msh_1 = Field('MSH_1') msh_2 = Field('MSH_2') self.assertRaises(IndexError, msh_1.to_er7) self.assertRaises(IndexError, msh_2.to_er7)
def test_to_string_msh_field_v27(self): for v in ('2.7', '2.8', '2.8.1', '2.8.2'): m = Message('OML_O33', version=v) msh = m.msh self.assertEqual(msh.msh_1.to_er7(), '|') self.assertEqual(msh.msh_2.to_er7(), '^~\\&#') msh_1 = Field('MSH_1') msh_2 = Field('MSH_2') self.assertRaises(IndexError, msh_1.to_er7) self.assertRaises(IndexError, msh_2.to_er7)
def test_wrong_datatype_field(self): """ Tests that if a field is not of the correct datatype the message is not validate The message used has the MSH_9 of type ST """ msg = self._create_message(self.adt_a01) msh_9 = Field('MSH_9', datatype='ST') msh_9.msh_9_1 = 'ADT_A01' msg.msh.msh_9 = msh_9 self.assertFalse(msg.validate())
def test_wrong_datatype_field(self): """ Tests that if a field is not of the correct datatype the message is not validate The message used has the MSH_9 of type ST """ msg = self._create_message(self.rsp_k21) msh_9 = Field('MSH_9', datatype='ST') msh_9.msh_9_1 = 'RSP_K21' msg.msh.msh_9 = msh_9 self.assertRaises(ValidationError, msg.validate, report_file=self.report_file) self._test_report_file('ERROR')
def test_z_segment(self): """ Tests that, after adding a Z segment to a valid message, the message is still valid """ msg = self._create_message(self.rsp_k21) msg.add_segment('zin') msg.zin = 'ZIN|aa|bb|cc|' zin_4 = Field('ZIN_4', datatype='CWE') zin_4.value = 'dd' msg.zin.zin_4 = zin_4 self.assertTrue(msg.validate())
def test_to_string_msh_field_v27_no_truncation(self): for v in ('2.7', '2.8', '2.8.1', '2.8.2'): m = Message('OML_O33', encoding_chars=DEFAULT_ENCODING_CHARS, version=v) msh = m.msh self.assertEqual(msh.msh_1.to_er7(), '|') self.assertEqual(msh.msh_2.to_er7(), '^~\\&') msh_1 = Field('MSH_1') msh_2 = Field('MSH_2') self.assertRaises(IndexError, msh_1.to_er7) self.assertRaises(IndexError, msh_2.to_er7)
def _populate_telecom_fields(segment: Segment, personal_telecom: str, work_telecom: str, telecom_list) -> None: for telecom in telecom_list: telecom_type = telecom.get("use", "") telecom_value = telecom.get("value", "") if telecom_type in ["home", "temp", "old", "mobile", ""]: telecom = personal_telecom else: telecom = work_telecom if telecom_value: telecom_field = Field(telecom) telecom_field.XTN_2 = _get_telecom_use_code(telecom_type) telecom_field.XTN_12 = telecom_value segment.add(telecom_field)
def test_assign_value_with_repetition(self): field_str = 'xxx~yyy' f = Field() f.value = field_str self.assertEqual(f.to_er7(), 'xxx\R\yyy') f = Field('PID_2') f.value = field_str self.assertEqual(f.to_er7(), 'xxx\R\yyy') f = Field('PID_2', validation_level=VALIDATION_LEVEL.STRICT) f.value = field_str self.assertEqual(f.to_er7(), 'xxx\R\yyy')
def test_assign_value_with_field_separator(self): field_str = 'xxx|yyy' escaped_str = 'xxx\F\yyy' f = Field('PID_3') f.value = field_str self.assertEqual(f.to_er7(), escaped_str) f = Field('PID_3', validation_level=VALIDATION_LEVEL.STRICT) f.value = field_str self.assertEqual(f.to_er7(), escaped_str) f = Field() f.value = field_str self.assertEqual(f.to_er7(), 'xxx\F\yyy')
def test_wrong_field(self): """ Tests that if there is an unexpected field the message in not validated The message used has an unexpected unknown field in the pid """ msg = self._create_message(self.rsp_k21) unkn_field = Field() msg.rsp_k21_query_response.pid.add(unkn_field) self.assertRaises(ValidationError, msg.validate, report_file=self.report_file) self._test_report_file('ERROR')
def test_wrong_z_segment(self): """ Tests that, if the Z segment doesn't follow HL7 rules, the message is not validated """ msg = self._create_message(self.adt_a01) msg.add_segment('zin') msg.zin = 'ZIN|aa|bb|cc|' # CX_1 is mandatory zin_4 = Field('ZIN_4', datatype='CX', version='2.6') zin_4.value = '^12' msg.zin.add(zin_4) self.assertRaises(ValidationError, msg.validate, report_file=self.report_file) del msg.zin.zin_4 # Z segment with unknown fields are not validated msg.zin.add(Field(version="2.6")) self.assertRaises(ValidationError, msg.validate, report_file=self.report_file) self._test_report_file('ERROR')
def test_wrong_z_segment(self): """ Tests that, if the Z segment doesn't follow HL7 rules, the message is not validated """ msg = self._create_message(self.adt_a01) msg.add_segment('zin') msg.zin = 'ZIN|aa|bb|cc|' # CX_1 is mandatory zin_4 = Field('ZIN_4', datatype='CX') zin_4.value = '^12' msg.zin.add(zin_4) self.assertRaises(ValidationError, msg.validate, report_file=self.report_file) del msg.zin.zin_4 # Z segment with unknown fields are not validated msg.zin.add(Field()) self.assertRaises(ValidationError, msg.validate, report_file=self.report_file) self._test_report_file('ERROR')
def test_add_more_components_to_base_datatype_field(self): f1 = Field('pid_8', validation_level=VALIDATION_LEVEL.STRICT) #this is a base datatype field f1.add(Component(datatype='IS')) self.assertRaises(MaxChildLimitReached, f1.add, Component(datatype='ST')) f2 = Field('pid_8') f2.add(Component(datatype='IS')) self.assertRaises(MaxChildLimitReached, f2.add, Component(datatype='ST'))
def test_assign_value(self): field_str = '1010110909194822^^^AUTH&1.3.6.1.4.1.21367.2011.2.5.17&ISO^PK' f = Field('PID_3') f.value = field_str parsed_field = parse_field(field_str, 'PID_3') self.assertEqual(f.to_er7(), parsed_field.to_er7()) f = Field('PID_3', validation_level=VALIDATION_LEVEL.STRICT) f.value = field_str self.assertEqual(f.to_er7(), parsed_field.to_er7()) f = Field('PID_1', validation_level=VALIDATION_LEVEL.STRICT) with self.assertRaises(MaxChildLimitReached): f.value = '1^2'
def test_to_string_segment_with_unknown_fields(self): f1 = Field() f1.value = 'abc' f2 = Field() f2.value = 'cba' pid_er7 = 'PID|1||566-554-3423^^^GHH^MR||SURNAME^NAME^A|||M|||1111 SOMEWHERE STREET^^SOMEWHERE^^^USA||555-555-2004~444-333-222|||M|||||||||||||||||||||||' pid = parse_segment(pid_er7) pid.add(f1) self.assertEqual(pid.to_er7(trailing_children=True), pid_er7 + '|abc') pid.add(f2) self.assertEqual(pid.to_er7(trailing_children=True), pid_er7 + '|abc|cba')
def parse_field(text, name=None, version=None, encoding_chars=None, validation_level=None, reference=None, force_varies=False): """ Parse the given ER7-encoded field and return an instance of :class:`hl7apy.core.Field`. :type text: ``basestring`` :param text: the ER7-encoded string containing the fields to be parsed :type name: ``basestring`` :param name: the field name (e.g. MSH_7) :type version: ``basestring`` :param version: the HL7 version (e.g. "2.5"), or ``None`` to use the default (see :func:`hl7apy.set_default_version`) :type encoding_chars: ``dict`` :param encoding_chars: a dictionary containing the encoding chars or None to use the default (see :func:`hl7apy.set_default_encoding_chars`) :param validation_level: the validation level. Possible values are those defined in :class:`hl7apy.consts.VALIDATION_LEVEL` class or ``None`` to use the default validation level (see :func:`hl7apy.set_default_validation_level`) :type reference: ``dict`` :param reference: a dictionary containing the element structure returned by :func:`hl7apy.load_reference` or :func:`hl7apy.find_reference` :return: an instance of :class:`hl7apy.core.Field` >>> field = "NUCLEAR^NELDA^W" >>> nk1_2 = parse_field(field, name="NK1_2") >>> print nk1_2 <Field NK1_2 (NAME) of type XPN> >>> print nk1_2.to_er7() NUCLEAR^NELDA^W >>> unknown = parse_field(field) >>> print unknown <Field of type None> >>> print unknown.to_er7() NUCLEAR^NELDA^W """ version = _get_version(version) encoding_chars = _get_encoding_chars(encoding_chars) if force_varies: reference = ('leaf', 'varies', None, None) try: field = Field(name, version=version, validation_level=validation_level, reference=reference) except InvalidName: field = Field(version=version, validation_level=validation_level, reference=reference) if name in ('MSH_1', 'MSH_2'): s = SubComponent(datatype='ST', value=text) c = Component(datatype='ST') c.add(s) field.add(c) else: children = parse_components(text, field.datatype, version, encoding_chars, validation_level) if Validator.is_quiet(validation_level) and is_base_datatype(field.datatype, version) and \ len(children) > 1: field.datatype = None field.children = children return field
def test_to_string_z_segment_with_unknown_fields(self): f1 = Field() f1.value = 'abc' f2 = Field() f2.value = 'cba' zin = Segment('ZIN') zin.zin_1 = 'yyy' zin.add(f1) self.assertEqual(zin.to_er7(), 'ZIN|yyy|abc') zin.zin_4 = 'zzz' self.assertEqual(zin.to_er7(), 'ZIN|yyy|||zzz|abc') zin.add(f2) self.assertEqual(zin.to_er7(), 'ZIN|yyy|||zzz|abc|cba')
def parse_field(text, name=None, version=None, encoding_chars=None, validation_level=None, reference=None, force_varies=False): """ Parse the given ER7-encoded field and return an instance of :class:`Field <hl7apy.core.Field>`. :type text: ``str`` :param text: the ER7-encoded string containing the fields to be parsed :type name: ``str`` :param name: the field name (e.g. MSH_7) :type version: ``str`` :param version: the HL7 version (e.g. "2.5"), or ``None`` to use the default (see :func:`set_default_version <hl7apy.set_default_version>`) :type encoding_chars: ``dict`` :param encoding_chars: a dictionary containing the encoding chars or None to use the default (see :func:`set_default_encoding_chars <hl7apy.set_default_encoding_chars>`) :type validation_level: ``int`` :param validation_level: the validation level. Possible values are those defined in :class:`VALIDATION_LEVEL <hl7apy.consts.VALIDATION_LEVEL>` class or ``None`` to use the default validation level (see :func:`set_default_validation_level <hl7apy.set_default_validation_level>`) :type reference: ``dict`` :param reference: a dictionary containing the element structure returned by :func:`load_reference <hl7apy.load_reference>` or :func:`find_reference <hl7apy.find_reference>` or belonging to a message profile :type force_varies: ``boolean`` :param force_varies: flag that force the fields to use a varies structure when no reference is found. It is used when a segment ends with a field of type varies that thus support infinite children :return: an instance of :class:`Field <hl7apy.core.Field>` >>> field = "NUCLEAR^NELDA^W" >>> nk1_2 = parse_field(field, name="NK1_2") >>> print(nk1_2) <Field NK1_2 (NAME) of type XPN> >>> print(nk1_2.to_er7()) NUCLEAR^NELDA^W >>> unknown = parse_field(field) >>> print(unknown) <Field of type None> >>> print(unknown.to_er7()) NUCLEAR^NELDA^W """ version = _get_version(version) encoding_chars = _get_encoding_chars(encoding_chars, version) validation_level = _get_validation_level(validation_level) try: field = Field(name, version=version, validation_level=validation_level, reference=reference) except InvalidName: if force_varies: reference = ('leaf', None, 'varies', None, None, -1) field = Field(name, version=version, validation_level=validation_level, reference=reference) else: field = Field(version=version, validation_level=validation_level, reference=reference) if name in ('MSH_1', 'MSH_2'): s = SubComponent(datatype='ST', value=text, validation_level=validation_level, version=version) c = Component(datatype='ST', validation_level=validation_level, version=version) c.add(s) field.add(c) else: children = parse_components(text, field.datatype, version, encoding_chars, validation_level, field.structure_by_name) if Validator.is_tolerant(validation_level) and is_base_datatype(field.datatype, version) and \ len(children) > 1: field.datatype = None field.children = children return field
def _populate_name_field(name_field: Field, name: dict) -> None: name_field.XPN_1 = name.get("family", "") if given_name := name.get("given"): name_field.XPN_2 = given_name[0] if len(given_name) > 1: name_field.XPN_3 = " ".join(given_name[1:])
def test_assign_value_unknown_field(self): field_str = '1010110909194822^^^AUTH&1.3.6.1.4.1.21367.2011.2.5.17&ISO^PK' f = Field() f.value = field_str
def test_add_empty_component(self): f1 = Field('pid_3', validation_level=VALIDATION_LEVEL.STRICT) self.assertRaises(ChildNotValid, f1.add, Component(datatype='ST')) f2 = Field('pid_3') f2.add(Component(datatype='ST'))
def test_override_field_containing_children_datatype(self): a = Field('pid_3') a.cx_1 = 'cx_1 value' a.cx_4 = 'cx_4 value' with self.assertRaises(OperationNotAllowed): a.datatype = 'HD'
def test_add_component(self): f = Field('PID_5') f.add_component('XPN_1') self.assertEqual(f.children[0].name,'XPN_1')
def test_override_field_datatype_strict(self): a = Field('pid_3', validation_level=VALIDATION_LEVEL.STRICT) with self.assertRaises(OperationNotAllowed): a.datatype = 'HD' self.assertRaises(OperationNotAllowed, Field, 'pid_3', datatype='HD', validation_level=VALIDATION_LEVEL.STRICT)
def create_unknown_subcomponent_by_get(self): f = Field('STF_2') with self.assertRaises(ChildNotFound): f.stf_2_10_100 = 'subcomponent'
def test_create_base_datatype_subcomponent_by_get(self): f = Field('STF_2') f.stf_2_10 = 'subcomponent'
def test_assign_value_traversal(self): cmp_str = 'xxx' f1 = Field('PID_39') f2 = Field('PID_39') f1.cwe_1.value = cmp_str f2.cwe_1 = cmp_str self.assertEqual(f1.to_er7(), f2.to_er7()) s1 = Segment('PID') s2 = Segment('PID') s1.pid_39.pid_39_1.value = cmp_str s2.pid_39.pid_39_1 = cmp_str complex_cmp_str = 'xxx&yyy&zzz' f1 = Field('PID_4') f2 = Field('PID_4') f1.cx_10.value = complex_cmp_str f2.cx_10 = complex_cmp_str self.assertEqual(f1.to_er7(), f2.to_er7()) s1.pid_4.pid_4_1.value = complex_cmp_str s2.pid_4.pid_4_1 = complex_cmp_str self.assertEqual(f1.to_er7(), f2.to_er7())
def _populate_nk1_segment(nk1: Segment, contact: dict, set_id: int) -> None: nk1.NK1_1 = str(set_id) if name := contact.get("name"): nk1_2 = Field("NK1_2") _populate_name_field(nk1_2, name) nk1.add(nk1_2)
def test_z_field(self): f = Field('zin_1') self.assertTrue(f.validate())
def parse_field(text, name=None, version=None, encoding_chars=None, validation_level=None, reference=None, force_varies=False): """ Parse the given ER7-encoded field and return an instance of :class:`Field <hl7apy.core.Field>`. :type text: ``str`` :param text: the ER7-encoded string containing the fields to be parsed :type name: ``str`` :param name: the field name (e.g. MSH_7) :type version: ``str`` :param version: the HL7 version (e.g. "2.5"), or ``None`` to use the default (see :func:`set_default_version <hl7apy.set_default_version>`) :type encoding_chars: ``dict`` :param encoding_chars: a dictionary containing the encoding chars or None to use the default (see :func:`set_default_encoding_chars <hl7apy.set_default_encoding_chars>`) :type validation_level: ``int`` :param validation_level: the validation level. Possible values are those defined in :class:`VALIDATION_LEVEL <hl7apy.consts.VALIDATION_LEVEL>` class or ``None`` to use the default validation level (see :func:`set_default_validation_level <hl7apy.set_default_validation_level>`) :type reference: ``dict`` :param reference: a dictionary containing the element structure returned by :func:`load_reference <hl7apy.load_reference>` or :func:`find_reference <hl7apy.find_reference>` or belonging to a message profile :type force_varies: ``boolean`` :param force_varies: flag that force the fields to use a varies structure when no reference is found. It is used when a segment ends with a field of type varies that thus support infinite children :return: an instance of :class:`Field <hl7apy.core.Field>` >>> field = "NUCLEAR^NELDA^W" >>> nk1_2 = parse_field(field, name="NK1_2") >>> print(nk1_2) <Field NK1_2 (NAME) of type XPN> >>> print(nk1_2.to_er7()) NUCLEAR^NELDA^W >>> unknown = parse_field(field) >>> print(unknown) <Field of type None> >>> print(unknown.to_er7()) NUCLEAR^NELDA^W """ version = _get_version(version) encoding_chars = _get_encoding_chars(encoding_chars) validation_level = _get_validation_level(validation_level) try: field = Field(name, version=version, validation_level=validation_level, reference=reference) except InvalidName: if force_varies: reference = ('leaf', 'varies', None, None) field = Field(name, version=version, validation_level=validation_level, reference=reference) else: field = Field(version=version, validation_level=validation_level, reference=reference) if name in ('MSH_1', 'MSH_2'): s = SubComponent(datatype='ST', value=text, validation_level=validation_level, version=version) c = Component(datatype='ST', validation_level=validation_level, version=version) c.add(s) field.add(c) else: children = parse_components(text, field.datatype, version, encoding_chars, validation_level, field.structure_by_name) if Validator.is_tolerant(validation_level) and is_base_datatype(field.datatype, version) and \ len(children) > 1: field.datatype = None field.children = children return field
def test_assign_value_with_overridden_datatype(self): a = Field('pid_3', 'CE') #official datatype is CX a.ce_1 = 'xyz' self.assertEqual(a.to_er7(), 'xyz')
def test_create_base_datatype_component_by_get(self): f = Field('SID_2') f.sid_2_1 = 'field' self.assertEqual(f.sid_2_1.to_er7(), 'field')
def _populate_address_field(address_field: Field, address: dict) -> None: if address_line_list := address.get("line"): address_field.XAD_1 = address_line_list[0] if len(address_line_list) > 1: address_field.XAD_2 = address_line_list[1]