Repository: cuthbertLab/music21 (python)

Issue:
Durationless element can get inserted twice; missing safeguard in coreGuardBeforeAddElement
**music21 version**

7


**Problem summary**
`makeMeasures` can insert the same element in a stream twice when the element coincides with the end of the stream. We made this change in #592 but didn't notice that it was inserting the identical element from the flat source into the newly created measure.


**Steps to reproduce**

```
>>> p = stream.Part()
>>> p.insert(4, meter.TimeSignature())
>>> p.makeMeasures(inPlace=True)
>>> for el in p.recurse():
...   print(el, id(el))
```

**Expected vs. actual behavior**
<music21.stream.Measure 1 offset=0.0> 4465547536
<music21.clef.TrebleClef> 4465548496
<music21.meter.TimeSignature 4/4> 4465547392
<music21.meter.TimeSignature 4/4> **4465410544**
<music21.bar.Barline type=final> 4465692736
<music21.meter.TimeSignature 4/4> **4465410544**

**More information**
This came up putting together the make measures patch for MIDI import, since the conductor track will only extend as far as the last element (which will be durationless time signature or key signature), and if we make measures, we choke here.

Making a deep copy before inserting might work, but in addition, I would think a safeguard is missing here? It wasn't obvious to me since `storeAtEnd` runs `coreGuardBeforeAddElement`.

Pull request description:
Prevent durationless element being inserted in last measure AND in end elements
Fixes #854 (on the assumption it would be too expensive to add guardrails to check all sites when inserting)

Before, a durationless element coinciding with the end of the stream would be added (on purpose) to the end elements, then (accidentally) also to the last measure.

Patch:
diff --git a/music21/stream/base.py b/music21/stream/base.py
index b2d0a7b27..1d41834f0 100644
--- a/music21/stream/base.py
+++ b/music21/stream/base.py
@@ -6480,7 +6480,7 @@ class Stream(core.StreamCoreMixin, base.Music21Object):
         '''
         This method calls a sequence of Stream methods on this Stream to prepare
         notation, including creating voices for overlapped regions, Measures
-        if necessary, creating ties, beams, and accidentals.
+        if necessary, creating ties, beams, accidentals, and tuplet brackets.
 
         If `inPlace` is True, this is done in-place;
         if `inPlace` is False, this returns a modified deep copy.
@@ -12964,7 +12964,7 @@ class Part(Stream):
         alteredPitches=None,
         cautionaryPitchClass=True,
         cautionaryAll=False,
-        inPlace=True,
+        inPlace=False,
         overrideStatus=False,
         cautionaryNotImmediateRepeat=True,
         tiePitchSet=None,
@@ -12974,7 +12974,7 @@ class Part(Stream):
         provides the management of passing pitches from
         a past Measure to each new measure for processing.
 
-        TODO: by default inPlace should be False
+        Changed in v.7 -- `inPlace` defaults False
         '''
         if not inPlace:  # make a copy
             returnObj = self.coreCopyAsDerivation('makeAccidentals')
diff --git a/music21/stream/makeNotation.py b/music21/stream/makeNotation.py
index 87456fffc..da1a92f47 100644
--- a/music21/stream/makeNotation.py
+++ b/music21/stream/makeNotation.py
@@ -610,6 +610,7 @@ def makeMeasures(
         if not match:
             if start == end == oMax:
                 post.storeAtEnd(e)
+                continue
             else:
                 raise stream.StreamException(
                     f'cannot place element {e} with start/end {start}/{end} within any measures')


Test patch:
diff --git a/music21/stream/tests.py b/music21/stream/tests.py
index 4817fff3c..96bc530e7 100644
--- a/music21/stream/tests.py
+++ b/music21/stream/tests.py
@@ -2044,7 +2044,7 @@ class Test(unittest.TestCase):
         obj = expressions.TextExpression('FREEZE')
         s.insert(3, obj)
         s.makeMeasures(inPlace=True)
-        self.assertEqual(len(s.measure(1).getElementsByClass('Expression')), 1)
+        self.assertEqual(len(s.flat.getElementsByClass('Expression')), 1)
 
     def testRemove(self):
         '''Test removing components from a Stream.