diff --git a/music21/musicxml/partStaffExporter.py b/music21/musicxml/partStaffExporter.py index b0f83fd5ae..368b13751e 100644 --- a/music21/musicxml/partStaffExporter.py +++ b/music21/musicxml/partStaffExporter.py @@ -214,6 +214,7 @@ def joinableGroups(self) -> List[StaffGroup]: staffGroups = self.stream.getElementsByClass('StaffGroup') joinableGroups: List[StaffGroup] = [] # Joinable groups must consist of only PartStaffs with Measures + # and exist in self.stream for sg in staffGroups: if len(sg) <= 1: continue @@ -221,6 +222,8 @@ def joinableGroups(self) -> List[StaffGroup]: continue if not all(p.getElementsByClass('Measure') for p in sg): continue + if not all(p in self.stream for p in sg): + continue joinableGroups.append(sg) # Deduplicate joinable groups (ex: bracket and brace enclose same PartStaffs) @@ -846,6 +849,19 @@ def testJoinPartStaffsE(self): self.assertEqual({staff.text for staff in m2tag.findall('note/staff')}, {'2'}) self.assertEqual({staff.text for staff in m3tag.findall('note/staff')}, {'1'}) + def testJoinPartStaffsF(self): + ''' + Flattening the score will leave StaffGroup spanners with parts no longer in the stream. + ''' + from music21 import corpus + from music21 import musicxml + sch = corpus.parse('schoenberg/opus19', 2) + + SX = musicxml.m21ToXml.ScoreExporter(sch.flat) + SX.scorePreliminaries() + SX.parsePartlikeScore() + # Previously, an exception was raised by getRootForPartStaff() + SX.joinPartStaffs() if __name__ == '__main__':