From 4f280ebfe0b9c8c75aee70d415a9be906d16c246 Mon Sep 17 00:00:00 2001 From: Cedric Conday Date: Tue, 30 Jun 2026 03:48:38 +0000 Subject: [PATCH] Allow assign_field() to descend into a simple (non-repeating) field (#55) A field parsed as a single value is stored as a bare string, so assign_field() addressing a repetition/component/subcomponent of it hit 'TypeError: str object does not support item assignment' when it tried to slice-assign into that string. Promote a bare string to a Repetition (and likewise a single-component repetition to a Component) before descending, preserving the existing value. Addresses item 1 of #55. --- hl7/containers.py | 14 ++++++++++++++ tests/test_parse.py | 21 +++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/hl7/containers.py b/hl7/containers.py index 1b1626b..73ace74 100644 --- a/hl7/containers.py +++ b/hl7/containers.py @@ -742,12 +742,26 @@ def assign_field( while len(field) < repeat_num: field.append(self.create_repetition([])) repetition = field(repeat_num) + if not isinstance(repetition, Repetition): + # A non-repeating field stores its value as a bare string. Promote + # it to a Repetition so it can be addressed at the component or + # subcomponent level instead of raising a TypeError. + repetition = self.create_repetition( + [repetition] if repetition != "" else [] + ) + field(repeat_num, repetition) if component_num is None: repetition[:] = [value] return while len(repetition) < component_num: repetition.append(self.create_component([])) component = repetition(component_num) + if not isinstance(component, Component): + # Likewise, a single-component repetition stores a bare string. + component = self.create_component( + [component] if component != "" else [] + ) + repetition(component_num, component) if subcomponent_num is None: component[:] = [value] return diff --git a/tests/test_parse.py b/tests/test_parse.py index 39cc786..faa0a25 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -356,6 +356,27 @@ def test_assign(self): self.assertEqual(msg2["MSH.21.1.1"], "COMPONENT 21.1.1") self.assertEqual(msg2["MSH.21.1.2.4"], "SUBCOMPONENT 21.1.2.4") + def test_assign_deeper_into_simple_field(self): + # Regression for #55: assigning into a field/repetition that was parsed + # as a bare string must promote it to a container rather than raising + # "TypeError: 'str' object does not support item assignment". + sample = "MSH|^~\\&|field|rep1~rep2|" + + # repetition level (the reported case) + seg = hl7.parse(sample).segments("MSH")[0] + seg.assign_field("NewRep", 3, 1) + self.assertEqual(str(seg(3)), "NewRep") + + # component level keeps the existing value as the first component + seg = hl7.parse(sample).segments("MSH")[0] + seg.assign_field("X", 3, 1, 2) + self.assertEqual(str(seg(3)), "field^X") + + # subcomponent level into a single-component repetition + seg = hl7.parse(sample).segments("MSH")[0] + seg.assign_field("Y", 4, 1, 1, 2) + self.assertEqual(str(seg(4)), "rep1&Y~rep2") + def test_unescape(self): msg = hl7.parse(rep_sample_hl7)