From 250fe764c43fef67bbcc8620c271ebd2b68192e5 Mon Sep 17 00:00:00 2001 From: eeshsaxena Date: Sun, 16 Aug 2026 11:01:50 +0530 Subject: [PATCH] Do not raise KeyError when dumping after a Format line redefinition A section may contain more than one Format line, and the last one wins for the section field order. Lines parsed under an earlier order do not carry the new field names, so dumping them looked up a missing field and raised KeyError even though parse_string had accepted the document. Fall back to an empty value for a field a line does not carry, so a parsed document always dumps. --- src/ass/line.py | 6 +++++- tests/test_ass.py | 13 +++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/ass/line.py b/src/ass/line.py index 5d1defc..5dbbc98 100644 --- a/src/ass/line.py +++ b/src/ass/line.py @@ -41,7 +41,11 @@ def dump(self, field_order=None): if field_order is None: field_order = self.DEFAULT_FIELD_ORDER - return ",".join(_Field.dump(self.fields[field]) + # A field in field_order that the line does not carry (for example when + # a section has a second "Format:" line that redefines the order after + # the lines were parsed) dumps as empty rather than raising KeyError. + return ",".join(_Field.dump(self.fields[field]) if field in self.fields + else "" for field in field_order) def dump_with_type(self, field_order=None): diff --git a/tests/test_ass.py b/tests/test_ass.py index 317880c..a3586bb 100755 --- a/tests/test_ass.py +++ b/tests/test_ass.py @@ -135,6 +135,19 @@ def test_custom_line_section_write(self, line_section): def test_custom_line_section_dump(self, line_section): assert "\n".join(line_section.dump()) == self.TEST_CUSTOM + def test_dump_after_format_redefinition(self): + # A second "Format:" line in a section redefines the field order after + # the lines were parsed; dumping such a document used to raise KeyError. + doc = ass.Document.parse_string(dedent("""\ + [Events] + Format: Layer, Start, End, Style, Text + Dialogue: 0,0:00:01.00,0:00:04.00,Default,Hello + Format: a""")) + out = StringIO() + doc.dump_file(out) + # the dumped document parses again without error + assert ass.Document.parse_string(out.getvalue()) is not None + class TestEvents: